一、基本概念
- 进程:系统中正在运行的应用程序。每个程序都是相互独立的,并且运行在一块独有的受保护的内存中
- 线程:进程基本执行路径。一个进程想要执行任务,就必须通过线程来执行。单条的线程通过串行的方式执行任务,也就是说任务是一个一个按顺序的执行
- 多线程:开启多条线程,让任务并发执行。(原理:在同一时间内,CPU 只会处理一条线程,多线程并发执行其实是,cpu在不同的线程之间快速的切换处理,只要cpu切换的足够快,就会给人多线程并发执行任务的假象)
补充:并行指的是任务一起执行,强调的是过程;并发指的是任务以一起执行的方式开始执行,强调的是任务开始执行的方式。
二、多线程的优缺点
优点
- 可提高程序的执行效率
- 可合理提高cpu和内存的利用率
缺点
- 开启一条线程所占用的内存较大(主线程 1M ;子线程 512KB)
- 线程多时,cpu在在切换线程上的开销较大,影响性能
- 线程间的通讯和数据共享等会将大程序设计的复杂度
三、多线程的实现方案
1. NSThread
此方案是经过苹果封装后完全面向对象的,可以直接拿到线程对象进行操作,很直观、便捷。但是缺点就是需手动管理线程生命周期,所以不经常使用
1.1 创建(3种方式)
// 1.手动启动线程,可拿到线程对象进行额外的设置
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(addThread:) object:@"hahaha"];
[thread start];
// 2.分离出子线程 - 自动启动线程
[NSThread detachNewThreadSelector:@selector(addChildThread:) toTarget:self withObject:@"子线程"];
// 3.后台线程 - 自动启动线程
[self performSelectorInBackground:@selector(addBackgroundThread:) withObject:@"后台线程"];
1.2 NSThread 常涉及到的方法
[thread cancel]; //取消线程
[NSThread exit];
[NSThread sleepForTimeInterval:3.0]; //阻塞线程
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:3.0]];
[NSThread currentThread]; //获取当前线程
[NSThread mainThread]; //获取主线程
[NSThread isMultiThreaded]; //是否是多线程,返回BOOL值
1.3 线程间通信
- (void)viewDidLoad {
[super viewDidLoad];
// 创建子线程
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(addThread:) object:@"hahaha"];
[thread start];
}
- (void)addThread:(NSString *)name {
NSLog(@"%@",[NSThread currentThread]);
// 在子线程中回到主线程的两种方式
[self performSelectorOnMainThread:@selector(goBackMainThread:) withObject:@"main" waitUntilDone:YES];
[self performSelector:@selector(goBackMainThread:) onThread:[NSThread mainThread] withObject:@"test" waitUntilDone:YES];
}
- (void)goBackMainThread:(NSString *)name {
NSLog(@"%@",[NSThread currentThread]);
}
打印结果
2016-08-01 14:20:30.253 demo[66988:3541822] <NSThread: 0x79e71ab0>{number = 2, name = (null)}
2016-08-01 14:20:30.258 demo[66988:3541733] <NSThread: 0x79e72a30>{number = 1, name = main}
2016-08-01 14:20:30.259 demo[66988:3541733] <NSThread: 0x79e72a30>{number = 1, name = main}
1.4 线程安全
当多个线程访问同一块资源时会发生数据安全问题,也称为线程同步 ,这时候就需要加互斥锁 @synchronized(self){}
2. GCD
苹果为多核并行运算开发的解决方案,它可以自动的利用cpu的内核,并且系统自动管理线程的生命周期
开发者要做的是将任务添加到队列中,系统会自动将队列中的任务按FIFO的原则取出任务(FIFO:先进先出,后进后出,如果以并发方式执行任务,则先出的任务还没结束前下一个的任务可以出列)
2.1 任务和队列的理解
任务:决定能不能开启新线程,分同步和异步任务两种
-同步:任务只能在当前的线程执行,不具备开启新线程的能力(同步任务比较霸道,必须在当前的分配任务执行完,才算把分配任务的任务结束,和后面说的死锁有关联)
-异步:任务可以在其它线程中执行,具备有开启新线程的能力
// 同步任务
dispatch_sync(dispatch_get_global_queue(0, 0), ^{
});
// 异步任务
dispatch_async(dispatch_get_global_queue(0, 0), ^{
});
队列:决定任务将以什么方式执行,分串行和并发队列两种
-串行:任务将一个接一个的执行(一个任务执行完才开始下一个任务)
-并发:多个任务可以并发(同时)执行,要在异步任务函数中才能有效
队列的创建
-串行:系统提供两种方式
// 1.系统提供的主队列
dispatch_queue_t mainQueue = dispatch_get_main_queue();
// 2.创建新的串行队列(参数1:队列名字,apple推荐使用com.example.myQueue的规则来命名队列,用于debug的时候追踪队列以便于调试,可以为空;
// 参数2:可以传人NULL或DISPATCH_QUEUE_SERIAL表示串行队列)
dispatch_queue_t queue = dispatch_queue_create("com.hhh.eatShit", NULL);
- 并发:系统提供两种方式
// 1.系统提供的全局队列(参数1:队列的优先级;参数2:传0即可)
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 2.创建新的并发队列
dispatch_queue_t queue = dispatch_queue_create("com.hhh.eatShit", DISPATCH_QUEUE_CONCURRENT);
2.2 GCD使用方式(任务和队列的结合方式)
- 异步任务+并发队列:使用频率高,开启多线程并发的执行任务
- 异步任务+串行队列:使用频率高,开启一条新线程,串行执行任务
- 同步任务+并发队列:基本不用,不开线程在当前线程串行执行任务我
- 同步任务+串行队列:基本不用,不开线程在当前线程串行执行任务我
- 异步任务+主队列:不开线程,在主线程中串行执行任务我
- 同步任务+主队列:不开线程,在主线程中串行执行任务我(注意死锁)
注意:在当前的串行队列中添加同步任务到当前队列会发生死锁
- (void)viewDidLoad {
[super viewDidLoad];
// 主队列是串行的,在主队里中往主队列添加同步任务,发生死锁,无法执行打印内容
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"快把我打印出来");
});
}
2.3 🍐演示GCD的使用
- 异步任务+并发队列
- (void)viewDidLoad {
[super viewDidLoad];
// 由系统决定开几条线程
dispatch_queue_t queue = dispatch_queue_create("com.demo.bingfa", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"任务1---%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"任务2---%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"任务3---%@",[NSThread currentThread]);
});
}
打印
2016-08-01 17:27:01.793 demo[79533:3667100] 任务1---<NSThread: 0x79858c40>{number = 2, name = (null)}
2016-08-01 17:27:01.793 demo[79533:3667104] 任务3---<NSThread: 0x7865da50>{number = 4, name = (null)}
2016-08-01 17:27:01.794 demo[79533:3667103] 任务2---<NSThread: 0x79a5a540>{number = 3, name = (null)}
2.异步任务+串行队列
- (void)viewDidLoad {
[super viewDidLoad];
// 只开一条新线程
dispatch_queue_t queue = dispatch_queue_create("com.demo.chuanxing", NULL);
dispatch_async(queue, ^{
NSLog(@"任务1---%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"任务2---%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"任务3---%@",[NSThread currentThread]);
});
}
打印
2016-08-01 17:29:13.092 demo[79710:3669166] 任务1---<NSThread: 0x7a236720>{number = 2, name = (null)}
2016-08-01 17:29:13.093 demo[79710:3669166] 任务2---<NSThread: 0x7a236720>{number = 2, name = (null)}
2016-08-01 17:29:13.094 demo[79710:3669166] 任务3---<NSThread: 0x7a236720>{number = 2, name = (null)}
3.同步任务+并发队列
- (void)viewDidLoad {
[super viewDidLoad];
// 不开新线程,当前是主线程,所以任务1、2、3在主线程中执行
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_async(queue, ^{
NSLog(@"任务1---%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"任务2---%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"任务3---%@",[NSThread currentThread]);
});
}
打印
2016-08-01 17:57:04.133 demo[81692:3691446] 任务1---<NSThread: 0x7a2314b0>{number = 1, name = main}
2016-08-01 17:57:04.134 demo[81692:3691446] 任务2---<NSThread: 0x7a2314b0>{number = 1, name = main}
2016-08-01 17:57:04.134 demo[81692:3691446] 任务3---<NSThread: 0x7a2314b0>{number = 1, name = main}
4.同步任务+串行队列
- (void)viewDidLoad {
[super viewDidLoad];
dispatch_queue_t queue = dispatch_queue_create("com.demo.chuanxing", NULL);
dispatch_async(queue, ^{
NSLog(@"新开的子线程---%@",[NSThread currentThread]);
// 在新开的子线程中,在queue队列中测试
dispatch_queue_t queue1 = dispatch_queue_create("com.demo.chuanxing", NULL);
dispatch_sync(queue1, ^{
NSLog(@"任务1---%@",[NSThread currentThread]);
});
dispatch_sync(queue1, ^{
NSLog(@"任务2---%@",[NSThread currentThread]);
});
dispatch_sync(queue1, ^{
NSLog(@"任务3---%@",[NSThread currentThread]);
});
});
}
打印
2016-08-01 17:53:10.405 demo[81376:3688029] 新开的子线程---<NSThread: 0x78e7fe80>{number = 2, name = (null)}
2016-08-01 17:53:10.406 demo[81376:3688029] 任务1---<NSThread: 0x78e7fe80>{number = 2, name = (null)}
2016-08-01 17:53:10.407 demo[81376:3688029] 任务2---<NSThread: 0x78e7fe80>{number = 2, name = (null)}
2016-08-01 17:53:10.407 demo[81376:3688029] 任务3---<NSThread: 0x78e7fe80>{number = 2, name = (null)}
5.异步任务+主队列(同3)
6.同步任务+主队列(切记不能在主队列中使用这种方式)
- (void)viewDidLoad {
[super viewDidLoad];
dispatch_queue_t queue = dispatch_queue_create("com.demo.chuanxing", NULL);
dispatch_async(queue, ^{
NSLog(@"新开的子线程---%@",[NSThread currentThread]);
// 在新开的子线程中,任务1、2、3在主线程中执行
dispatch_queue_t queue1 = dispatch_get_main_queue();
dispatch_sync(queue1, ^{
NSLog(@"任务1---%@",[NSThread currentThread]);
});
dispatch_sync(queue1, ^{
NSLog(@"任务2---%@",[NSThread currentThread]);
});
dispatch_sync(queue1, ^{
NSLog(@"任务3---%@",[NSThread currentThread]);
});
});
}
打印
2016-08-01 17:59:57.794 demo[81900:3693593] 新开的子线程---<NSThread: 0x79745ab0>{number = 2, name = (null)}
2016-08-01 17:59:57.798 demo[81900:3693419] 任务1---<NSThread: 0x79843a10>{number = 1, name = main}
2016-08-01 17:59:57.799 demo[81900:3693419] 任务2---<NSThread: 0x79843a10>{number = 1, name = main}
2016-08-01 17:59:57.800 demo[81900:3693419] 任务3---<NSThread: 0x79843a10>{number = 1, name = main}
2.4 GCD其它函数
- 栅栏函数 dispatch_barrier_async(queue, ^{ });
在任务前面的异步任务都执行完后才会执行它,并且等它执行完后,后面的异步任务才能开始执行
注意:
1.>此函数加入全局队列示无效的,即queue不能是全剧队列
2.>如果任务是同步的则会在当前的线程中执行,异步的话在新线程中执行
🍐
- (void)viewDidLoad {
[super viewDidLoad];
dispatch_queue_t queue = dispatch_queue_create("com.demo.bingfa", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"任务1---%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"任务2---%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"任务3---%@",[NSThread currentThread]);
});
dispatch_barrier_async(queue, ^{
NSLog(@"任务4---%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"任务5---%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"任务6---%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"任务7---%@",[NSThread currentThread]);
});
}
打印(任务4总是在任务1、2、3和5、6、7的中间)
2016-08-01 20:55:44.075 demo[85715:3735784] 任务2---<NSThread: 0x7a8746e0>{number = 3, name = (null)}
2016-08-01 20:55:44.075 demo[85715:3735778] 任务1---<NSThread: 0x7a96ff10>{number = 2, name = (null)}
2016-08-01 20:55:44.075 demo[85715:3735777] 任务3---<NSThread: 0x7a67a470>{number = 4, name = (null)}
2016-08-01 20:55:44.077 demo[85715:3735777] 任务4---<NSThread: 0x7a67a470>{number = 4, name = (null)}
2016-08-01 20:55:44.078 demo[85715:3735777] 任务5---<NSThread: 0x7a67a470>{number = 4, name = (null)}
2016-08-01 20:55:44.078 demo[85715:3735778] 任务6---<NSThread: 0x7a96ff10>{number = 2, name = (null)}
2016-08-01 20:55:44.078 demo[85715:3735784] 任务7---<NSThread: 0x7a8746e0>{number = 3, name = (null)}
信号量的使用 --- 但以上任务2中存在其它异步并发任务,如网络请求的时:
dispatch_queue_t queue = dispatch_queue_create("com.demo.bingfa", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
// 创建一个信号量为0的信号(红灯)
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
dispatch_queue_t queue2 = dispatch_queue_create("com.demo.bing", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue2, ^{
[NSThread sleepForTimeInterval:2];
// 使信号的信号量+1,这里的信号量本来为0,+1信号量为1(绿灯)
dispatch_semaphore_signal(sema);
NSLog(@"任务2---%@",[NSThread currentThread]);
});
NSLog(@"任务2---%@",[NSThread currentThread]);
// 开启信号等待,设置等待时间为永久,直到信号的信号量大于等于1(绿灯)
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
});
dispatch_async(queue, ^{
NSLog(@"任务3---%@",[NSThread currentThread]);
});
dispatch_barrier_async(queue, ^{
NSLog(@"任务4---%@",[NSThread currentThread]);
});
2.队列组
能实现在一个或则多个任务执行完之后,在执行特定的任务。例如:A任务和B任务并发执行,C任务需要在A任务和B任务都执行完之后再执行,这时候就可以通过队列组来实现
🍐
- (void)viewDidLoad {
[super viewDidLoad];
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"任务1---%@",[NSThread currentThread]);
});
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"任务2---%@",[NSThread currentThread]);
});
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"任务3---%@",[NSThread currentThread]);
});
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"任务4---%@",[NSThread currentThread]);
});
dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"任务5---%@",[NSThread currentThread]);
});
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"任务6---%@",[NSThread currentThread]);
});
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"任务7---%@",[NSThread currentThread]);
});
}
打印: 你会发现任务5永远都是队列组中最后执行的一个
2016-08-01 22:10:55.218 demo[90162:3774195] 任务1---<NSThread: 0x7af959d0>{number = 2, name = (null)}
2016-08-01 22:10:55.218 demo[90162:3774194] 任务2---<NSThread: 0x7b1346f0>{number = 3, name = (null)}
2016-08-01 22:10:55.218 demo[90162:3774216] 任务6---<NSThread: 0x7b06cf00>{number = 6, name = (null)}
2016-08-01 22:10:55.218 demo[90162:3774215] 任务4---<NSThread: 0x7af95fe0>{number = 5, name = (null)}
2016-08-01 22:10:55.218 demo[90162:3774199] 任务3---<NSThread: 0x7ae30250>{number = 4, name = (null)}
2016-08-01 22:10:55.219 demo[90162:3774217] 任务7---<NSThread: 0x7b135bb0>{number = 7, name = (null)}
2016-08-01 22:10:55.220 demo[90162:3774217] 任务5---<NSThread: 0x7b135bb0>{number = 7, name = (null)}
3.NSOperation
3.1 概念
NSOperation是对GCD的封装;本身是一个抽象类,只能使用它的三个子类;和NSOperationQueue结合使用实现多线程并发
3.2 NSOperation和NSOperationQueue的理解
NSOperation三个子类
-NSInvocationOperation
- (void)viewDidLoad {
[super viewDidLoad];
// 不加入队列执行开始操作
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(addOperation:) object:@"NEW"];
[operation start];
}
- (void)addOperation:(NSString *)name {
// 在主线程中执行,没有意义
NSLog(@"%@",[NSThread currentThread]);
}
-NSBlockOperation
创建操作时携带的任务在主线程,操作后面额外添加的任务,系统自动开启线程执行
- (void)viewDidLoad {
[super viewDidLoad];
// 不加入队列执行开始操作
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
// 在主线程中执行
NSLog(@"任务1---%@",[NSThread currentThread]);
}];
[operation addExecutionBlock:^{
// 系统根据需要自动开启线程
NSLog(@"任务2---%@",[NSThread currentThread]);
}];
[operation addExecutionBlock:^{
// 系统根据需要自动开启线程
NSLog(@"任务3---%@",[NSThread currentThread]);
}];
[operation addExecutionBlock:^{
// 系统根据需要自动开启线程
NSLog(@"任务4---%@",[NSThread currentThread]);
}];
[operation start];
}
-自定义NSOperation
一般操作过于复杂时可以使用自定义NSOperation,具有隐蔽性和可重复利用的好处
#import "JYOperation.h"
@implementation JYOperation
- (void)main {
NSLog(@"%@",[NSThread currentThread]);
}
@end
- (void)viewDidLoad {
[super viewDidLoad];
// 不添加到队列的话,任务在主线程执行,没有意义
JYOperation *operation = [[JYOperation alloc] init];
[operation start];
}
NSOperationQueue
- 主队列
添加到主队列中的任务都在主线程中执行
-非主队列
任务在子线程中执行,控制任务以串行或并发的方式执行,具体通过设置队列的maxConcurrentOperationCount(最大并发数)属性来控制
注意:
1.maxConcurrentOperationCount必须在操作添加到队列之前设置才有效
2.maxConcurrentOperationCount 默认为-1,即默认任务是并发执行;等于0时,不执行任务,无意义;等于1时,串行执行任务;等于n时,并发数为n,允许n个任务是同时执行的
- (void)viewDidLoad {
// 2.非主队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = 3;
[queue addOperationWithBlock:^{
NSLog(@"任务1---%@",[NSThread currentThread]);
}];
[queue addOperationWithBlock:^{
NSLog(@"任务2---%@",[NSThread currentThread]);
}];
[queue addOperationWithBlock:^{
NSLog(@"任务3---%@",[NSThread currentThread]);
}];
[queue addOperationWithBlock:^{
NSLog(@"任务4---%@",[NSThread currentThread]);
}];
[queue addOperationWithBlock:^{
NSLog(@"任务5---%@",[NSThread currentThread]);
}];
[queue addOperationWithBlock:^{
NSLog(@"任务6---%@",[NSThread currentThread]);
}];
}
打印
2016-08-02 10:10:56.874 demo[99820:3887770] 任务1---<NSThread: 0x7a98b340>{number = 2, name = (null)}
2016-08-02 10:10:56.874 demo[99820:3887814] 任务3---<NSThread: 0x7a71c690>{number = 4, name = (null)}
2016-08-02 10:10:56.874 demo[99820:3887769] 任务2---<NSThread: 0x7a71c450>{number = 3, name = (null)}
2016-08-02 10:10:56.875 demo[99820:3887814] 任务5---<NSThread: 0x7a71c690>{number = 4, name = (null)}
2016-08-02 10:10:56.876 demo[99820:3887810] 任务6---<NSThread: 0x7a71c840>{number = 5, name = (null)}
2016-08-02 10:10:56.876 demo[99820:3887770] 任务4---<NSThread: 0x7a98b340>{number = 2, name = (null)}
3.3 操作和队列结合(两种方式)
- (void)viewDidLoad {
// 方式1:将操作加入队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"任务1---%@",[NSThread currentThread]);
}];
[queue addOperation:operation];
// 方式2:通过队列直接加操作
[queue addOperationWithBlock:^{
NSLog(@"任务2---%@",[NSThread currentThread]);
}];
}
补充(暂停、恢复和取消)
- (void)viewDidLoad {
self.queue = [[NSOperationQueue alloc] init];
// 任务暂停后可以恢复执行
if (self.queue.isSuspended) {
self.queue.suspended = NO;
}
// 任务取消后不可在恢复执行
[self.queue cancelAllOperations];
}
3.4 设置操作依赖
通过调用操作[operation addDependency:]方法,可实现不同操作按指定的顺序执行
- (void)viewDidLoad {
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"操作1---");
}];
NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"操作2---");
}];
// operation1依赖operation2,operation2执行完才能执行operation1
[operation1 addDependency:operation2];
[queue addOperation:operation1];
[queue addOperation:operation2];
}
打印
2016-08-02 11:02:19.161 demo[3839:3930104] 操作2---
2016-08-02 11:02:19.162 demo[3839:3930104] 操作1---
🍐有一种需求:前两个异步任务都执行完之后才开始执行第三个
任务
- (void)viewDidLoad {
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"操作1---");
}];
NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"操作2---");
}];
NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"操作3---");
}];
[operation3 addDependency:operation1];
[operation3 addDependency:operation2];
[queue addOperation:operation1];
[queue addOperation:operation2];
[queue addOperation:operation3];
}
打印
2016-08-02 11:05:21.480 demo[4099:3932866] 操作2---
2016-08-02 11:05:21.480 demo[4099:3932865] 操作1---
2016-08-02 11:05:21.482 demo[4099:3932865] 操作3---
4 总结
以上主要涉及到开发中常用的一些内容,另外至于GCD和NSOperation线程间的通信,其实常用到的是异步操作后回到主线程,只要将需要回到主线程的任务添加到主队列即可
网友评论