IOS有三种多线程编程技术,分别是:
1)NSThread
2)Cocoa NSOperation
3)GCD(Grand Central Dispatch)
这三种编程方式从上到下,抽象层次从低到高,抽度越高越简单,也是Apple最推荐使用的。
三种方式的优缺点介绍
1)NSThread
优点:比其他两种轻量级
缺点:需要自己管理线程的生命周期,线程同步。线程同步对数据加锁会有一定的系统开销。
2)Cocoa NSOperation
优点:不需要关心线程管理,数据同步的事情,可以把精力放在自己需要执行的操作上。
Cocoa Operation相关的类是NSOperation, NSOperationQueue。NSOperation是个
抽象类,使用它必须用它的子类,可以试想他活着使用它定义好的两个字类:
NSInvocationOperation和NSBlockOperation。创建NSOperation子类的对象把对象添
加到NSOperationQueue对了里执行。
3)GCD
Grand Central Dispatch是Apple开发的一个多核编程解决方法。在IOS4.0中发布。GCD是一个
替代注入NSThread,NSOperationQueue,NSInvocationOperation的技术的很高效和强大的技
术。现在IOS系统升级到9了,所以不用担心该技术不能使用。
三种方式的使用
1)NSThread:NSThread有两种创方式
第一种是类方法,第二种是实例方法1、[NSThread detachNewThreadSelector:@selector(doSomething:) toTarget:self withObject:nil]; 2、NSThread* myThread = [[NSThread alloc] initWithTarget:self selector:@selector(doSomething:) object:nil]; [myThread start];
参数的意义:
selector:线程执行的方法,这个selector只能有一个参数,而且不能有返回值。
target:selector消息发送的对象
argument:传输给target的唯一参数,也可以是nil
不显示创建线程的方法:
用NSObject的类方法performSelectorInBackground:withObject:创建一个线程:
[Obj performSelectorInBackground:@selector(doSomething) withObject:nil];
2)Cocoa NSOperation的使用
使用NSOperation的方式有两种:一种是用定义好的两个子类:NSInvocationOperation和
NSBlockOperation。另一种是继承NSOperation。如果你也熟悉Java,NSOperation就和
Runnable很相似。NSOperation也是设计用来扩展的,只需要继承重写NSOperation的一
个方法main。相当于Java中的Run方法。然后把NSOperation子类的对象放入NSOperationQueue
队列中,该队列就会启动并开始处理它。
下面看一个例子:
#import "ViewController.h" #define kURL @"http://avatar.csdn.net/2/C/D/1_totogo2010.jpg" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; NSInvocationOperation *operation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(downloadImage:) object:kURL]; NSOperationQueue *queue = [[NSOperationQueue alloc]init]; [queue addOperation:operation]; // Do any additional setup after loading the view, typically from a nib. } -(void)downloadImage:(NSString *)url{ NSLog(@"url:%@", url); NSURL *nsUrl = [NSURL URLWithString:url]; NSData *data = [[NSData alloc]initWithContentsOfURL:nsUrl]; UIImage * image = [[UIImage alloc]initWithData:data]; [self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES]; } -(void)updateUI:(UIImage*) image{ self.imageView.image = image; }
3)GCD的介绍和使用
介绍:Grand Central Dispatch简称GCD是苹果公司开发的技术,以优化的应用程序支持多核新处理器
和其他的对称多处理系统的系统。这建立在任务并行执行的线程池模式的基础上的。它首次发布
在Mac OS X 10.6 iOS4上。
设计:GCD的工作原理是:让程序平行排队的特定任务,根据可用的处理资源,安排他们在任何可用处
理器核心上执行任务。一个任务可以是一个函数或者是一个block。GCD底层依然是用线程实现,不过
这样可以让程序员不必关注实现细节。其中的FIFO队列称为dispatch queue,他可以保证先进先执行。
dispatch queue分为下面三种:
(1)Serial:同时只执行一个任务。通常用于同步访问特定的数据或资源。当创建多个serial queue时,
queue之间是并发执行的。
(2)Concurrent:又称为global dispatch queue,可以并发地执行多任务,但是执行完成的顺序是随机的。
(3)Main:他是全局可用的serial queue,他在应用程序的主线程上执行。
使用:
(1)常用的方法dispatch_async
为了避免界面在处理耗时操作是卡死,比如读取网络数据,IO,数据库读写等。我们会在另外一个线程
中处理这些操作,然后通知主线程更新界面。
下面是例子:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSURL * url = [NSURL URLWithString:@"http://avatar.csdn.net/2/C/D/1_totogo2010.jpg"]; NSData * data = [[NSData alloc]initWithContentsOfURL:url]; UIImage *image = [[UIImage alloc]initWithData:data]; if (data != nil) { dispatch_async(dispatch_get_main_queue(), ^{ self.imageView.image = image; }); } });
系统给每个应用程序提供三个concurrent dispatch queues。 这三个并发调度队列是全局的,他们只有优先级
不同。应为是全局的所以我们不用去创建他。我们只需要通过函数dispatch_get_global_queue去取得队列。
(2)dispatch_group_async的使用
他可以实现监听一组任务是否完成,完成后得到通知执行其他操作。这方法很有用,比如你执行三个下载任务
当三个任务都完成后你才通知界面说完成了。下面是例子:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_group_t group = dispatch_group_create(); dispatch_group_async(group, queue, ^{ [NSThread sleepForTimeInterval:1]; NSLog(@"group1"); }); dispatch_group_async(group, queue, ^{ [NSThread sleepForTimeInterval:2]; NSLog(@"group2"); }); dispatch_group_async(group, queue, ^{ [NSThread sleepForTimeInterval:3]; NSLog(@"group3"); }); dispatch_group_notify(group, dispatch_get_main_queue(), ^{ NSLog(@"updateUi"); }); dispatch_release(group);
下面是打印结果:
2016-07-25 16:04:16.737 gcdTest[43328:11303] group1 2016-07-25 16:04:17.738 gcdTest[43328:12a1b] group2 2016-07-25 16:04:18.738 gcdTest[43328:13003] group3 2016-07-25 16:04:18.739 gcdTest[43328:f803] updateUi
(3)dispatch_barrier_async的使用
他是在前面的任务执行结束后才执行,而且他后面的任务等待它执行完成后才执行,下面是一段例子:
dispatch_queue_t queue = dispatch_queue_create("gcdtest.rongfzh.yc", DISPATCH_QUEUE_CONCURRENT); dispatch_async(queue, ^{ [NSThread sleepForTimeInterval:2]; NSLog(@"dispatch_async1"); }); dispatch_async(queue, ^{ [NSThread sleepForTimeInterval:4]; NSLog(@"dispatch_async2"); }); dispatch_barrier_async(queue, ^{ NSLog(@"dispatch_barrier_async"); [NSThread sleepForTimeInterval:4]; }); dispatch_async(queue, ^{ [NSThread sleepForTimeInterval:1]; NSLog(@"dispatch_async3"); });
打印结果:
2016-07-25 16:20:33.967 gcdTest[45547:11203] dispatch_async1 2016-07-25 16:20:35.967 gcdTest[45547:11303] dispatch_async2 2016-07-25 16:20:35.967 gcdTest[45547:11303] dispatch_barrier_async 2016-07-25 16:20:40.970 gcdTest[45547:11303] dispatch_async3
(4)dispatch_apply
执行某段代码N次,下面是例子:
dispatch_apply(5, globalQ, ^(size_t index) { // 执行5次 });