一、NSThread 每一个NSThread对象对应一个线程,量级较轻(真正的多线程) 如下两点是苹果专门开发的“并发”技术,使得程序员能够再也不去关心线程的具体使用问题 二、NSOperation/NSOperationQueue 面向对象的线程技术 三、GCD —— Grand Central Dispatch(派发) 是基于C语言的框架,能够充分利用多核,是苹果推荐使用的多线程技术程序员
以上这三种编程方式从上到下,抽象度层次是从低到高的,抽象度越高的使用越简单,也是Apple最推荐使用的。可是就目前而言,iOS的开发者,须要了解三种多线程技术的基本使用过程。由于不少框架技术分别使用了不一样多线程技术。编程
NSThread: 优势:NSThread 比其余两个轻量级,使用简单 缺点:须要本身管理线程的生命周期、线程同步、加锁、睡眠以及唤醒等。线程同步对数据的加锁会有必定的系统开销 NSOperation: 不须要关心线程管理,数据同步的事情,能够把精力放在本身须要执行的操做上 NSOperation是面向对象的 GCD: Grand Central Dispatch是由苹果开发的一个多核编程的解决方案。iOS4.0+才能使用,是替代NSThread, NSOperation的高效和强大的技术 GCD是基于C语言的多线程
NSObject的多线程方法——后台线程并发
(void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg 一般,因为线程管理相对比较繁琐,而不少耗时的任务又没法知道其准确的完成时间,所以可使用performSelectorInBackground方法直接新建一个后台线程,并将选择器指定的任务在后台线程执行,而无需关心具体的NSThread对象 提示: performSelectorInBackground方法自己是在主线程中执行的,而选择器指定的方法是在后台线程中进行的 使用performSelectorInBackground方法调用的任务能够更新UI界面 在大型交互式游戏中框架
(void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait; 若是要更新UI界面,能够在后台线程中调用performSelectorOnMainThread方法 提示:尽管使用performSelectorInBackground方法调用的任务能够更新UI界面,可是在实际开发中,涉及到UI界面的更新操做,仍是要使用performSelectorOnMainThread方法,以免没必要要的麻烦异步
<!-- lang: cpp -->async
- (IBAction)bigTask
{ // 本方法中的全部代码都是在主线程中执行的 // NSObject多线程技术 NSLog(@"执行前->%@", [NSThread currentThread]);函数
// performSelectorInBackground是将bigDemo的任务放在后台线程中执行 [self performSelectorInBackground:@selector(bigDemo) withObject:nil]; NSLog(@"执行后->%@", [NSThread currentThread]);
// [self bigDemo];spa
NSLog(@"执行完毕");
}线程
NSThread建立线程方法:
(id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument; 参数说明: selector:线程执行的方法,只能有一个参数,不能有返回值 target:selector消息发送的对象 argument:传输给target的惟一参数,也能够是nil
<!-- lang: cpp -->
// 成员方法 NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(bigDemo) object:nil];
// 启动start线程 [thread start];
NSOperation & NSOperationQueue NSOperation的两个子类 NSInvocationOperation NSBlockOperation 工做原理: 用NSOperation封装要执行的操做 将建立好的NSOperation对象放NSOperationQueue中 启动OperationQueue开始新的线程执行队列中的操做 注意事项: 使用多线程时一般须要控制线程的并发数,由于线程会消耗系统资源,同时运行的线程过多,系统会变慢 使用如下方法能够控制并发的线程数量: (void)setMaxConcurrentOperationCount:(NSInteger)cnt;
<!-- lang: cpp --> NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(opAction) object:nil]; // 若是使用start,会在当前线程启动操做
// [op1 start];
// 1. 一旦将操做添加到操做队列,操做就会启动 [_queue addOperation:op1]; <!-- lang: cpp --> // 用block的最大好处,能够将一组相关的操做,顺序写在一块儿,便于调试以及代码编写 [_queue addOperationWithBlock:^{ NSLog(@"%@", [NSThread currentThread]); // 模拟延时 [NSThread sleepForTimeInterval:1.0f]; // 模拟获取到图像 UIImage *image = [UIImage imageNamed:@"头像1"]; // 设置图像,在主线程队列中设置 [[NSOperationQueue mainQueue] addOperationWithBlock:^{ _imageView.image = image; }]; }];
GCD是基于C语言的框架 工做原理: 让程序平行排队的特定任务,根据可用的处理资源,安排它们在任何可用的处理器上执行任务 要执行的任务能够是一个函数或者一个block 底层是经过线程实现的,不过程序员能够没必要关注实现的细节 GCD中的FIFO队列称为dispatch queue,能够保证先进来的任务先获得执行 dispatch_notify 能够实现监听一组任务是否完成,完成后获得通知 GCD队列: 全局队列:全部添加到主队列中的任务都是并发执行的 串行队列:全部添加到串行队列中的任务都是顺序执行的 主队列:全部添加到主队列中的任务都是在主线程中执行的
全局队列(可能会开启多条线程) dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 串行队列(只可能会开启一条线程) dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL); 主队列 dispatch_get_main_queue();
异步操做 dispatch_async 在其余线程执行任务,会开启新的线程 异步方法没法肯定任务的执行顺序 同步操做 dispatch_sync 在当前在当前线程执行任务,不开启新的线程 同步操做与队列无关 同步方法会依次执行,可以决定任务的执行顺序 更新界面UI时,最好使用同步方法
GCD的优势: 充分利用多核 全部的多线程代码集中在一块儿,便于维护 GCD中无需使用@autoreleasepool 若是要顺序执行,可使用dispatch_sync同步方法 dispatch_async没法肯定任务的执行顺序
<!-- lang: cpp --> // 1. 队列 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 2. 将任务异步(并发)执行 dispatch_async(queue, ^{ NSLog(@"a->%@", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"b->%@", [NSThread currentThread]); }); dispatch_async(dispatch_get_main_queue(), ^{ NSLog(@"main - > %@", [NSThread currentThread]); });