(转载)原文地址:http://anxonli.iteye.com/blog/1097777
隔上一次写iPad app开发文章已经是10个月,那篇iPad app开发概述还不错,曾经成为了google关键字“iPad app 开发”搜索的第一位,可能是大牛们都太忙于赚app store的钱了,留下我这个小虾来写文章。这次的文章集中与iOS的多核编程和内存管理,为什么?因为iPad 2已经是双核CPU了!虽然iPad 1的应用已经不慢了,但大家完全可以使用苹果的多核编程框架来写出更加responsive的应用。
多核运算
在iOS中concurrency编程的框架就是GCD(Grand Central Dispatch), GCD的使用非常简单。它把任务分派到不同的queue队列来处理。开发者把任务代码装到一个个block里面,操作系统把这些任务代码分派到不同的资源里去处理,一个简单的例子来说,为什么初学者写tableview的时候,滑动列表时总会很卡,因为很多初学者把图片装载放到main thread主线程去执行,例如我们要滑动畅顺的话,iOS最快可以1秒内刷新60次,如何你的一个cell的文字和图片装载超过1/60秒的话,自然就会卡。所以一般我们会把图片装载这些需要多点时间的移出main thread来处理,对于用GCD来说,就是把图片载入放到另外一个queue队列中来异步执行,当资源准备好了后,放回到main thread中显示出来。main thread在GCD中就是main queue。
创建一个新queue队列的代码:
例如,我们图片读取放到network_queue来进行异步执行
dispatch_async的意思就是将任务进行异步并行处理,不一定需要一个任务处理完后才能处理下一个。以上代码loadMyImageFromNetwork的意思就是从网络中读取图片,这个任务交给network_queue来处理。这样读取图片的时间过长也不会阻塞主线程界面的处理。
当我们处理完图片后,应该更新界面,从queue的概念去设计,就是要将更新界面的代码放到main queue中去,因为iOS里面永远是主线程来刷新重画UI。所以代码应该为,
dispatch_get_main_queue() 函数就是返回主线程,^{} 封装的就是任务代码,这样嵌套方式就可以从一个队列queue,跳到另一个queue,就是这么简单。
我们一般可以把networking有关的代码放到一个queue,把图片resize的代码放到另外一个queue,处理完后更新界面,只需要嵌套跳回到 main queue。这样加上几行代码,你的程序就可以利用到系统多核资源,把具体的调度工作交给了操作系统自己来分配。有了这样的代码,不管你的硬件是单核,双核还是iMac的4核,甚至8核,都可以非常好地并行处理。
内存管理
我一直惊叹iOS和Objective-C内存处理能力,例如iPad版本的iWork,Pages应用就是一个内存处理技术应用的鬼斧神工之作。想想256M内存的iPad,可以带来如此的华丽的界面同时获得如此流畅的用户体验,真是不简单。原因就是iOS一直提倡开发者在有限硬件资源内写出最优化的代码,使用CPU最少,占用内存最小。
(以下代码适用于iOS SDK 4.1, 由于新SDK 4.2对内存使用有新改动,所以可能有不同。。。)
1. 尽量少的UIView层
通常我们喜欢把很多控件层(UILabel,UIButton,UIView等)一起放到一个大的UIView容器来显示我们的内容,这个方法一般是可以的,但是如果要经常重新刷新内容的大区域界面,多数发生在iPad的应用中,这个方法会带来过多的内存使用和动画的延迟(比较卡),例如,scrollview的动画比较卡,又或者,经常收到内存警告。其中一个重要原因是每个控件,特别是透明底的,会多次重新绘制(drawRect)过多。其解决办法是,尽量将几个控件合并到一个层上来显示,这样系统会减少系统调用drawRect,从而带来性能上的提升。
很简单的一个例子,就是iNotes提供手写功能,用户可以在iPad屏幕上写出不同的笔画,开始的设计是,用户每写一划,iNotes就会生成一个新的透明底UIView来保持这个笔画,用户写了10笔,系统就生产了10个UIView,每个view的大小都是整个屏幕的,以便用户的undo操作。这个方案带来严重的内存问题,因为系统将每个层都保持一个bitmap图,一个像素需要4bit来算,一个层的大小就是 4x1024x768 ~ 3M, 10个层就是 10x3M = 30M,很明显,iPad很快爆出内存警告。
这个例子最后的方案是,所有笔画都画在同一个层,iNotes可以保存笔画的点进行undo操作。这样的方案就是无论用户画多少笔画,界面重画需要的资源都是一样的。
2. 显示最佳尺寸的图片
很多程序员比较懒,网络上拿下来的图片,直接就用UIImageView将其显示给用户,这样的后果就是,程序需要一直保存着大尺寸的图片到内存。解决办法应该是先将图片缩小到需要显示的尺寸,释放大尺寸图片的内存,然后再显示到界面给用户。
3. 尽量使用图片pattern,而不是一张大的图片
例如,很多界面设计者喜欢在界面上放一个大底图,但这个底图是老是占用着内存的,最佳方案是,设计出一个小的pattern图,然后用这个方案显示成底图。
4. 使用完资源后,立即释放
一般objective-c的习惯是,用完的资源要立即释放,因为明白什么时候用完某个资源的是程序员你自己。
例如,我们要读较大的图片,把它缩小后,显示到界面去。当大图片使用完成后,应该立即释放。代码如下:
5. 循环中大量生成的自动释放autorelease对象,可以考虑使用autorelease pool封装
代码范例:
自动释放对象池把每个循环内生成的临时对象使用完后立即释放
以上的意见是本人多年来编写iPad/iPhone程序的经验,另外iOS4.0的multi-tasking特性发布后,程序可以被调入后台运行,苹果工程师的意见是,进入后台运行时,你的应用应该释放掉能释放的对象,尽量保持在16M左右,这样别的程序运行时才不容易把你的应用挤掉。
--------------------------------------------------
太久没有写东西了,中文写作能力退步了,大家别见怪,多给给意见
隔上一次写iPad app开发文章已经是10个月,那篇iPad app开发概述还不错,曾经成为了google关键字“iPad app 开发”搜索的第一位,可能是大牛们都太忙于赚app store的钱了,留下我这个小虾来写文章。这次的文章集中与iOS的多核编程和内存管理,为什么?因为iPad 2已经是双核CPU了!虽然iPad 1的应用已经不慢了,但大家完全可以使用苹果的多核编程框架来写出更加responsive的应用。
多核运算
在iOS中concurrency编程的框架就是GCD(Grand Central Dispatch), GCD的使用非常简单。它把任务分派到不同的queue队列来处理。开发者把任务代码装到一个个block里面,操作系统把这些任务代码分派到不同的资源里去处理,一个简单的例子来说,为什么初学者写tableview的时候,滑动列表时总会很卡,因为很多初学者把图片装载放到main thread主线程去执行,例如我们要滑动畅顺的话,iOS最快可以1秒内刷新60次,如何你的一个cell的文字和图片装载超过1/60秒的话,自然就会卡。所以一般我们会把图片装载这些需要多点时间的移出main thread来处理,对于用GCD来说,就是把图片载入放到另外一个queue队列中来异步执行,当资源准备好了后,放回到main thread中显示出来。main thread在GCD中就是main queue。
创建一个新queue队列的代码:
dispatch_queue_t network_queue; network_queue = dispatch_queue_create("com.myapp.network", nill);
例如,我们图片读取放到network_queue来进行异步执行
dispatch_async(network_queue, ^{ UIImage *cellImage = [self loadMyImageFromNetwork:image_url]; // 将图片cache到本地 [self cacheImage:cellImage]; ..... } );
dispatch_async的意思就是将任务进行异步并行处理,不一定需要一个任务处理完后才能处理下一个。以上代码loadMyImageFromNetwork的意思就是从网络中读取图片,这个任务交给network_queue来处理。这样读取图片的时间过长也不会阻塞主线程界面的处理。
当我们处理完图片后,应该更新界面,从queue的概念去设计,就是要将更新界面的代码放到main queue中去,因为iOS里面永远是主线程来刷新重画UI。所以代码应该为,
dispatch_async(network_queue, ^{ UIImage *cellImage = [self loadMyImageFromNetwork:image_url]; // 将图片cache到本地 [self cacheImage:cellImage]; // 回到主线程 dispatch_async(dispatch_get_main_queue(), ^{ // 显示图片到界面 [self displayImageToTableView:cellImage]; }]; } );
dispatch_get_main_queue() 函数就是返回主线程,^{} 封装的就是任务代码,这样嵌套方式就可以从一个队列queue,跳到另一个queue,就是这么简单。
我们一般可以把networking有关的代码放到一个queue,把图片resize的代码放到另外一个queue,处理完后更新界面,只需要嵌套跳回到 main queue。这样加上几行代码,你的程序就可以利用到系统多核资源,把具体的调度工作交给了操作系统自己来分配。有了这样的代码,不管你的硬件是单核,双核还是iMac的4核,甚至8核,都可以非常好地并行处理。
内存管理
我一直惊叹iOS和Objective-C内存处理能力,例如iPad版本的iWork,Pages应用就是一个内存处理技术应用的鬼斧神工之作。想想256M内存的iPad,可以带来如此的华丽的界面同时获得如此流畅的用户体验,真是不简单。原因就是iOS一直提倡开发者在有限硬件资源内写出最优化的代码,使用CPU最少,占用内存最小。
(以下代码适用于iOS SDK 4.1, 由于新SDK 4.2对内存使用有新改动,所以可能有不同。。。)
1. 尽量少的UIView层
通常我们喜欢把很多控件层(UILabel,UIButton,UIView等)一起放到一个大的UIView容器来显示我们的内容,这个方法一般是可以的,但是如果要经常重新刷新内容的大区域界面,多数发生在iPad的应用中,这个方法会带来过多的内存使用和动画的延迟(比较卡),例如,scrollview的动画比较卡,又或者,经常收到内存警告。其中一个重要原因是每个控件,特别是透明底的,会多次重新绘制(drawRect)过多。其解决办法是,尽量将几个控件合并到一个层上来显示,这样系统会减少系统调用drawRect,从而带来性能上的提升。
很简单的一个例子,就是iNotes提供手写功能,用户可以在iPad屏幕上写出不同的笔画,开始的设计是,用户每写一划,iNotes就会生成一个新的透明底UIView来保持这个笔画,用户写了10笔,系统就生产了10个UIView,每个view的大小都是整个屏幕的,以便用户的undo操作。这个方案带来严重的内存问题,因为系统将每个层都保持一个bitmap图,一个像素需要4bit来算,一个层的大小就是 4x1024x768 ~ 3M, 10个层就是 10x3M = 30M,很明显,iPad很快爆出内存警告。
这个例子最后的方案是,所有笔画都画在同一个层,iNotes可以保存笔画的点进行undo操作。这样的方案就是无论用户画多少笔画,界面重画需要的资源都是一样的。
2. 显示最佳尺寸的图片
很多程序员比较懒,网络上拿下来的图片,直接就用UIImageView将其显示给用户,这样的后果就是,程序需要一直保存着大尺寸的图片到内存。解决办法应该是先将图片缩小到需要显示的尺寸,释放大尺寸图片的内存,然后再显示到界面给用户。
3. 尽量使用图片pattern,而不是一张大的图片
例如,很多界面设计者喜欢在界面上放一个大底图,但这个底图是老是占用着内存的,最佳方案是,设计出一个小的pattern图,然后用这个方案显示成底图。
UIImage *smallImage = [[UIImage alloc] initWithContentsOfFile:path]; backgroundView.backgroundColor = [UIColor colorWithPatternImage:smallImage]; [smallImage release];
4. 使用完资源后,立即释放
一般objective-c的习惯是,用完的资源要立即释放,因为明白什么时候用完某个资源的是程序员你自己。
例如,我们要读较大的图片,把它缩小后,显示到界面去。当大图片使用完成后,应该立即释放。代码如下:
UIImage *fullscreenImage = [[UIImage alloc] initWithContentOfFile:path]; UIImage *smallImage = [self resizeImage:fullscreenImage]; [fullscreenImage release]; imageView.image = smallImage; ......
5. 循环中大量生成的自动释放autorelease对象,可以考虑使用autorelease pool封装
代码范例:
for(UIView *subview in bigView.subviews) { // 使用autorelease pool自动释放对象池 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; UIImageView *imageView = (UIImageView *)subview; // subview处理代码 ....... // 销毁自动释放对象 [pool drain]; }
自动释放对象池把每个循环内生成的临时对象使用完后立即释放
以上的意见是本人多年来编写iPad/iPhone程序的经验,另外iOS4.0的multi-tasking特性发布后,程序可以被调入后台运行,苹果工程师的意见是,进入后台运行时,你的应用应该释放掉能释放的对象,尽量保持在16M左右,这样别的程序运行时才不容易把你的应用挤掉。
--------------------------------------------------
太久没有写东西了,中文写作能力退步了,大家别见怪,多给给意见
发表评论
-
如何使用AV Foundation从摄像头将视频帧捕获为图像
2012-11-15 17:21 7453如果译错,感谢指出。 英文原文地址:https://d ... -
iOS单元测试
2012-11-05 11:37 916转自:http://www.cnblogs.com/ke ... -
Core Data数据持久化的使用
2012-10-30 21:31 1045CoreData 是ios中用来对数据做持久化的一个框架 ... -
ASIHTTPRequest缓存策略的设置
2012-10-30 17:23 3871ASIHTTPRequest 是一款强大的网络请求框架,该框架 ... -
【无限互联】xcode自定义类的模板
2012-10-23 19:37 1154翻译:http://www.bobmccune.com/ ... -
【无限互联】适配iOS6和iPhone5屏幕
2012-10-23 18:05 24731. iOS6的mo模拟器比较大,通过comman ... -
【无限互联】mac下配置svn服务器
2012-10-22 13:30 767在mac下配置svn服务器其实很简单,只需要简单的几句命令就可 ... -
【无限互联】iOS开发之多线程开发
2012-10-10 17:41 1233本节要点: 1.多线程的概念 2.掌握iOS中多线程 ... -
【无限互联】iOS开发block用法之UIAlertView控件的修改
2012-10-10 17:06 2682原始的UIAlertView的需要通过委托方法来实现按钮 ... -
Objective-C新特性
2012-09-05 14:38 701基于Xcode4.4(不完全独有)。1. 成员方法无需前置声明 ... -
iphone-NSDate日期处理
2012-08-31 16:25 1064NSDate存储的是世界标准时(UTC),输出时需要 ... -
iphone开发资源汇总
2012-08-31 16:16 1604如何用Facebook graphic api上传视 ... -
iOS-如何让xcode自动检查内存泄露
2012-08-31 16:05 1093在project-setting中找到 “Run Static ... -
UIScrollView的属性总结
2012-02-08 15:58 4429在滚动过程当中,其实是在修改原点坐标 当手指触摸后, scr ... -
iPhone开发之 ARC是什么
2012-01-17 16:58 1376相关链接:http://blog.csdn ... -
画图时 自己做的一小笔记
2012-01-07 21:02 9580 CGContextRef context = UIGra ... -
让Xcode 4.2生成的app支持旧版iOS设备(armv6)
2012-01-07 00:46 1333这几天遇到一个非常奇怪的问题,基于Xcode 4.2开发的ap ... -
5个开源库的JSON解析速度测试
2011-12-03 23:15 1457iOS5新增了JSON解析的API ... -
获取iOS设备当前ip地址
2011-11-17 23:16 1383第一种方法是用系统api的方式获取,如下 #include & ... -
Quartz 2D编程指南(2) - 图形上下文(Graphics Contexts)
2011-11-12 00:08 1447一个Graphics Context表示一 ...
相关推荐
多核编程和内存管理是iOS开发中不可或缺的技术。通过合理利用GCD,开发者可以轻松地处理并发问题,并充分利用多核处理器的能力。同时,良好的内存管理可以确保应用稳定运行,并提升用户体验。希望本文能帮助您更好地...
《Objective-C高级编程:iOS与OS X多线程和内存管理》是一本深入探讨Apple平台开发中的关键技术的书籍。本书主要围绕Objective-C语言在iOS和OS X操作系统上的应用,特别是针对多线程和内存管理这两个核心主题进行...
- **创建和管理DispatchQueue** - **获得全局并发DispatchQueue**:通过 `dispatch_get_global_queue` 函数获取。 - **创建串行DispatchQueue**:使用 `dispatch_queue_create` 函数创建。 - **运行时获得公共...
开发者应当学会如何使用GCD和Operation Queues来替代传统的线程创建和管理,以及如何将现有的基于锁的代码和循环代码迁移到新的并发编程模型中。 在iOS并发编程的学习过程中,初学者除了要掌握上述基础知识点之外,...
iOS提供了多种方式来创建和管理线程,包括使用NSThread、POSIX的多线程、Cocoa程序中的NSObject类方法,以及在Cocoa程序上面使用POSIX线程。 #### 1.5 设计技巧 在多线程编程中,避免创建过多的线程,确保线程合理...
NSThread是轻量级的线程实现,可以直接创建和管理线程。虽然使用起来相对简单,但需要手动管理线程的生命周期,不推荐在现代iOS开发中广泛使用。 五、 NSRunLoop NSRunLoop是iOS事件循环的核心,处理用户交互和其他...
通过 Storyboard,开发者可以直观地拖放 UI 控件,创建和管理视图控制器之间的导航关系。 5. **ARC (Automatic Reference Counting)**:iOS 5 引入的自动引用计数技术,简化了内存管理,降低了手动管理内存的复杂性...
创建和管理调度队列,添加任务到队列中,挂起和恢复调度队列都是移动应用开发中需要考虑的问题。使用 dispatch 信号量控制可用的有限资源,可以使得程序更加高效。 第五章 调度源 Dispatch Source 是 iOS 平台下...
该芯片包含了40个核心,采用Tensica的Xtensa架构,使用90nm工艺,集成8亿个晶体管,并且具有DDR2内存和TCAM,支持10GBPS SPI4.2数据报文接口,通过Crossbar Switch进行片内互联,以及ESI进行片外互联,体现了多核...
- **Grand Central Dispatch (GCD)**:GCD是一个多核编程的解决方案,可以帮助开发者优化应用性能,使其能够高效地处理多个任务。 #### 五、最佳实践 - **架构模式**:推荐使用MVC (Model-View-Controller) 或 ...
线程成本指的是创建和管理线程所需要消耗的系统资源,包括CPU时间、内存等。创建线程的方式包括使用NSThread类、POSIX的多线程、以及通过NSObject来生成线程。配置线程属性包括设置线程的堆栈大小、线程本地存储等。...
在iOS应用开发中,有效地管理任务调度对于优化性能、减轻CPU和内存负担至关重要。Swift作为Apple的首选编程语言,提供了一系列工具和最佳实践来帮助开发者实现这一目标。本篇文章将深入探讨如何使用Swift来创建一个...
在多线程编程方面,本书可能详细介绍了如何使用Objective-C来创建和管理多个线程,以及如何在线程间共享数据而不引起冲突。多线程编程是一种编程范式,它允许同时运行两个或更多部分的代码。在多核处理器上,多线程...
GCD 是 Grand Central Dispatch 的缩写, 是 Apple 开发的一个多核编程的解决方法。GCD 可以处理诸如数据锁定和资源泄漏等复杂的异步编程问题。 GCD 的主要特点是: 1. 高效强大:GCD 是一个高效强大的技术,可以...
8. **Core Data**:Apple的持久化框架,用于存储和管理应用程序的数据。Core Data提供了一个模型层,简化了数据的管理,并且支持关系数据库的特性。 9. **动画与过渡**:iOS应用中的动画可以增强用户体验。通过Core...
1. **内存管理**:深入讲解Objective-C和Swift中的内存管理机制,如ARC(Automatic Reference Counting)和弱引用,以及如何避免内存泄漏和过度消耗。 2. **多线程与并发**:介绍GCD(Grand Central Dispatch)、...