iOS-----使用NSOperation与NSOperationQueue实现多线程
使用NSOperation与NSOperationQueue实现多线程
NSOperation与NSOperationQueue的基本理论如下。
NSOperationQueue |
代表一个FIFO的队列,它负责管理系统提交的多个NSOperation,NSOperationQueue底层维护一个线程池,会按顺序启动线程来执行提交给该队列的NSOperation任务 |
|
NSOperation |
代表一个多线程任务。NSOperation还有NSInvocationOperation、NSBlockOperation两个子类。NSOperation有两种使用方式:①开发者实现NSOperation的子类;②开发者直接使用NSInvocationOperation或NSBlockOperation子类。 |
|
使用NSOperation、NSOperationQueue开发多线程非常简单,只要如下两步 |
||
1 |
创建NSOperationQueue队列,并为该队列设置相关属性。 |
|
2 |
创建NSOperation子类的对象,并将该对象提交给NSOperationQueue队列,该队列将会按顺序依次启用每个NSOperation。 |
|
NSOperationQueue负责管理、执行所有的NSOperation,它底层维护着一个线程池,开发者提交的NSOperation正是由该线程池中的线程负责执行的。NSOperationQueue提供了如下常用方法。 |
||
使用NSInvocationOperation和NSBlockOperation
NSInvocationOperation和NSBlockOperation都是NSOperation的子类,都可在程序中直接使用,用于封装需要异步执行的任务。
NSInvocationOperation和NSBlockOperation在用法上非常相似,区别是NSInvocationOperation用于将特定对象的特定方法封装成NSOperation,而NSBlockOperation则用于将代码封装成NSOperation。
创建NSInvocationOperation的代码片段如下:
创建NSBlockOperation的代码片段如下:
一旦得到NSOperation对象之后,将NSOperation对象提交给NSOperationQueue即可。
实例:使用NSBlockOperation下载图片
下面是该实例的视图控制器类的实现部分代码。
1 @implementation ViewController 2 3 NSOperationQueue* queue; 4 5 - (void)viewDidLoad 6 7 { 8 9 [super viewDidLoad]; 10 11 queue = [[NSOperationQueue alloc] init]; 12 13 // 设置该队列最大支持10个并发线程 14 15 queue.maxConcurrentOperationCount = 10; 16 17 } 18 19 - (IBAction)clicked:(id)sender 20 21 { 22 23 NSString* url = @” http://pic14.nipic.com/20110522/7411759_164157418126_2.jpg”; 24 25 // 以传入的代码块作为执行体,创建NSOperation 26 27 NSBlockOperation* operation = [NSBlockOperation blockOperationWithBlock:^{ 28 29 // 从网络获取数据 30 31 NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]]; 32 33 // 将网络数据初始化为UIImage对象 34 35 UIImage *image = [[UIImage alloc] initWithData: data]; 36 37 if(image != nil) 38 39 { 40 41 // 在主线程中执行updateUI:方法 42 43 [self performSelectorOnMainThread:@selector(updateUI:) 44 45 withObject:image waithUntilDone:YES];// ① 46 47 } 48 49 else 50 51 { 52 53 NSLog(@”---下载图片出现错误---”); 54 55 } 56 57 }]; 58 59 // 将NSOperation添加给NSOperationQueue 60 61 [queue addOperation:operation]; 62 63 } 64 65 - (void)updateUI:(UIImage*)image 66 67 { 68 69 self.iv.image = image; 70 71 } 72 73 @end
该程序创建了一个NSBlockOperation对象,接下来将该对象提交给NSOperationQueue即可.由于该代码块将会在线程中执行,因此程序在①号代码处调用了performSelectorOnMainThread:withObject: waitUntilDone:方法在主线程中更新iv控件显示的图片.
定义NSOperation子类
NSOperation一般不会直接拿来使用,而是选择创建它的子类,创建NSOperation的子类需要重写一个方法:- (void)main,该方法的方法将作为NSOperationQueue完成的任务。
下面程序示范了使用NSOperation的子类来下载网络图片。该示例的界面与前面介绍的使用NSThread下载图片的界面基本相似,只是该程序将会使用NSOperation的子类来启动多线程执行下载。该示例的界面上同样只有一个UIImageView和一个UIButton,程序为UIButton的“Touch Up Inside”时间绑定clicked:事件处理方法。
下面是LCDownImageOperation类的接口部分代码。
代 码 片 段 |
1 LCDownLoadImageOperation.h文件 2 3 #import<Foundation/Foundation.h> 4 5 // 定义NSOperation的子类 6 7 @interface LCDownImageOperation:NSOperation 8 9 @property (nonatomic, strong)NSURL* url; 10 11 @property (nonatomic, weak)UIImageView* imageView; 12 13 - (id)initWithURL:(NSURL*)url imageView:(UIImageView*)iv; 14 15 @end 16 17 LCDownLoadImageOperation.m文件 18 19 @implementation LCDownLoadImageOperation 20 21 - (id)initWithURL:(NSURL*)url imageView:(UIImageView*)iv 22 23 { 24 25 self = [super init]; 26 27 if(self) 28 29 { 30 31 _imageView = iv; 32 33 _url = url; 34 35 } 36 37 return self; 38 39 } 40 41 // 重写main方法,该方法将作为线程执行体 42 43 - (void)main 44 45 { 46 47 // 从网络获取数据 48 49 NSData *data = [[NSData alloc] initWithContentsOfURL:self.url]; 50 51 // 将网络数据初始化为UIImage对象 52 53 UIImage *image = [[UIImage alloc] initWithData;data]; 54 55 if(image !=nil) 56 57 { 58 59 // 在主线程中执行updateUI:方法 60 61 [self performSelectorOnMainThread:@selector(updateUI:) 62 63 withObject:image waitUntilDone:YES];// ① 64 65 } 66 67 else 68 69 { 70 71 NSLog(@”+++下载图片出现错误+++”); 72 73 } 74 75 } 76 77 - (void)updateUI:(UIImage*)image 78 79 { 80 81 self.imageView.image = image; 82 83 } 84 85 @end
|
说明 |
上面的代码创建了NSOperation类的子类,并重写了main方法,该方法将会作为该NSOperation所启动线程的执行体----也就是代表该线程要完成的任务.由于main方法的代码将会在新线程中执行,因此程序同样调用了performSelectorOnMainThread:withObject:waitUntilDone:方法在主线程中更新iv控件显示的图片.
|
代码片段 |
创建了该NSOperation的子类之后,接下来只要创建该子类的实例,并将它提交给NSOperationQueue即可.视图控制器类的实现部分使用了LCDownImageOperation从网络下载图片.下面是视图控制器类的实现部分代码. 1 ViewController.m 2 3 @implementation ViewController 4 5 NSOperationQueue *queue; 6 7 - (void)viewDidLoad 8 9 { 10 11 [super viewDidLoad]; 12 13 queue = [[NSOperationQueue alloc] init]; 14 15 // 设置该队列最大支持10个并发线程 16 17 queue.maxConcurrentOperationCount = 10; 18 19 } 20 21 - (IBAction)clicked:(id)sender 22 23 { 24 25 // 定义要加载的图片的URL 26 27 NSURL *url = [NSURL URLWithString:@” http://img2.imgtn.bdimg.com/it/u=194240101,2532182839&fm=21&gp=0.j pg”]; 28 29 // 创建LCDownImageOperation对象 30 31 LCDownImageOperation* operation = [[LCDownImageOperation alloc] initWithURL:url imageView:self.iv]; 32 33 // 将NSOperation的子类的实例提交给NSOperationQueue 34 35 [queue addOperation:operation]; 36 37 } 38 39 @end
|
说明 |
上面程序中的代码就是使用LCDownImageOperation实现多线程下载的关键代码,只要创建LCDownImageOperation实例,然后将该实例提交给NSOperationQueue即可.
|
小结 |
iOS提供了3种多线程支持:①使用NSThread开发多线程应用;②使用GCD实现多线程;③使用NSOperation和NSOperationQueue实现多线程. |
|
|
********************************************************************************* 如需转载请注明出处---聰,地址为:http://www.cnblogs.com/congli0220/