iOS block并发
多核运算
在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对内存使用有新改动,所以可能有不同。。。)
尽量少的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操作。这样的方案就是无论用户画多少笔画,界面重画需要的资源都是一样的。
显示最佳尺寸的图片
很多程序员比较懒,网络上拿下来的图片,直接就用UIImageView将其显示给用户,这样的后果就是,程序需要一直保存着大尺寸的图片到内存。解决办法应该是先将图片缩小到需要显示的尺寸,释放大尺寸图片的内存,然后再显示到界面给用户。
尽量使用图片pattern,而不是一张大的图片
例如,很多界面设计者喜欢在界面上放一个大底图,但这个底图是老是占用着内存的,最佳方案是,设计出一个小的pattern图,然后用这个方案显示成底图。
UIImage *smallImage = [[UIImage alloc] initWithContentsOfFile:path];
backgroundView.backgroundColor = [UIColor colorWithPatternImage:smallImage];
[smallImage release];
使用完资源后,立即释放
一般objective-c的习惯是,用完的资源要立即释放,因为明白什么时候用完某个资源的是程序员你自己。例如,我们要读较大的图片,把它缩小后,显示到界面去。当大图片使用完成后,应该立即释放。代码如下:
UIImage *fullscreenImage = [[UIImage alloc] initWithContentOfFile:path];
UIImage *smallImage = [self resizeImage:fullscreenImage];
[fullscreenImage release];
imageView.image = smallImage;……
循环中大量生成的自动释放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左右,这样别的程序运行时才不容易把你的应用挤掉。
、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
iphone开发过程中,如果遇到加载大数据或者涉及到网络通信情况时,就需要在后台线程来完成这些事情。
除了NSThread之外,iphone还提供了一套GCD机制帮助开发者来实现多线程开发。
同NSThread相比,GCD的运行效率更高,开发更简单。
GCD的基础是dispatch queue和block。
1. block可以简单理解为一个任务。block在程序中的表现形式类似:
1 NSString * URL = @"......";
2
3 ^{
4
5 UIImage * image = [UIImage imageWithURL:URL];
6
7 };
从上例可以看出,block可以引用外部作用域的数据。这也是很block和普通函数的区别,block会保存当前执行的上下文。
2. dispatch queue是一个FIFO任务队列,可以将一些block压入这个队列中,系统会按照顺序来执行这些block。
dispatch_async()
系统中默认提供了三种dispatch queue:
a. Main. 如果某个block希望在主线程完成,可以将其push到main dispatch queue中。
b. Concurrent. 系统会自动创建三个不同优先级的dispatch queue。不能保证block严格按照顺序执行。
c. Serial. 需要用户手动创建,能够保证block严格按照push的顺序执行。
下面是一段异步加载网络图像的例子:
1 UIImageView * imageView = [[UIImageView alloc] init];
2
3 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
4
5 UIImage * image = ;//网络拉取代码
6
7 dispatch_async(dispatch_get_main_queue (), ^{
8
9 imageView.image = image; // 在主线程中更新imageview
10
11 });
12
13 });
从以上代码可以看出,GCD的前后台线程同步通知机制要比NSThread优雅和方便很多。
iOS block并发的更多相关文章
- iOS -NSOperation并发编程
http://www.cocoachina.com/game/20151201/14517.html http://blog.csdn.net/qinlicang/article/details/42 ...
- iOS Block界面反向传值
在上篇博客 <iOS Block简介> 中,侧重解析了 iOS Block的概念等,本文将侧重于它们在开发中的应用. Block是iOS4.0+ 和Mac OS X 10.6+ 引进的对C ...
- iOS block从零开始
iOS block从零开始 在iOS4.0之后,block横空出世,它本身封装了一段代码并将这段代码当做变量,通过block()的方式进行回调. block的结构 先来一段简单的代码看看: void ...
- iOS block 机制
本文要将block的以下机制,并配合具体代码详细描述: block 与 外部变量 block 的存储域:栈块.堆块.全局块 定义 块与函数类似,只不过是直接定义在另一个函数里,和定义它的那个函数共享同 ...
- ios Block详细用法
ios Block详细用法 ios4.0系统已开始支持block,在编程过程中,blocks被Obj-C看成是对象,它封装了一段代码,这段代码可以在任何时候执行.Blocks可以作为函数参数或者函数的 ...
- iOS Block的本质(四)
iOS Block的本质(四) 上一篇文章iOS Block的本质(三)中已经介绍过block变量的捕获,本文继续探寻block的本质. 1. block内修改变量的值 int main(int ar ...
- # iOS Block的本质(三)
iOS Block的本质(三) 上一篇文章iOS Block的本质(二)中已经介绍过block变量的捕获,本文继续探寻block的本质. 1. block对对象变量的捕获,ARC 环境 block一般 ...
- iOS Block的本质(二)
iOS Block的本质(二) 1. 介绍引入block本质 通过上一篇文章Block的本质(一)已经基本对block的底层结构有了基本的认识,block的底层就是__main_block_impl_ ...
- iOS Block的本质(一)
iOS Block的本质(一) 1.对block有一个基本的认识 block本质上也是一个oc对象,他内部也有一个isa指针.block是封装了函数调用以及函数调用环境的OC对象. 2.探寻block ...
随机推荐
- 使用JavaMail发送邮件和接受邮件
转载:http://blog.csdn.net/zdp072/article/details/30977213 一. 为什么要学习JavaMail 为什么要学习JavaMail开发? 现在很多WEB应 ...
- 【转】notepad++ 应用学习 -- 列模式,十六进制模式
Notepad++ 顾名思义,是一个比notepad(Windows下叫记事本)的功能更强的编辑器. 总以为notepad++小巧轻盈,而且开源,要比UE(UltraEdit)好用.因为她支持的视 ...
- 关于Apache Struts 2 S2-032高危漏洞的一些确认
2016年4月21日Struts2官方发布两个CVE,其中CVE-2016-3081(S2-032)官方评级为高. 主要原因为在用户开启动态方法调用的情况下,会被攻击者实现远程代码执行攻击. 具体的漏 ...
- 列出man手册所有函数的方法
locate /man7/|sed -r 's#.*/([^/]+).7.gz$#\1#' locate /man7/ | xargs basename -a -s '.7.gz' apropos - ...
- uva 993 Product of digits (贪心 + 分解因子)
Product of digits For a given non-negative integer number N , find the minimal natural Q such tha ...
- How to remove spaces of a string with regular expression
left 's/^\s*//g' right 's/\s*$//g' all 's/\s+//g'
- C#读取注册表信息
注册表是视窗系统的一个核心的数据库,在这个数据库中存放中与系统相关的各种参数,这些参数直接控制中系统的启动.硬件的驱动程序安装信息以及在视窗系统上运行的各种应用程序的注册信息等.这就意味着,如果注册表 ...
- 基于邻接表的广度优先搜索遍历(bfs)
题目:http://acm.sdut.edu.cn/sdutoj/showproblem.php?pid=2142&cid=1186 #include<stdio.h> #incl ...
- vijosp1507郁闷的出纳员
一道平衡树实现的名次树,用了treap实现. 1.rand()产生的数可能比INF大,很可能改变树的结构. 2.删除时先递归,然后再删除自己,实现就变得简单多了. 3.因为很多情况树会是空的,所以设了 ...
- 8.8-8.10 usaco
summary:44 没救了...整天刷水迟早药丸! ❤bzoj3892: 区间dp.我原来的思路是dp[i][j]表示前i个数跳过了j次,那么转移可以前k个数转移了j-1次,枚举k就好了,但是这样是 ...