1. pthread

pthreadPOSIX线程的简称,是线程的POSIX标准。pthread基于C语言,是一种可以跨平台使用的方法,但是由于其使用难度较大,并且生命周期需要程序员手动管理,因此很少或几乎不用

  1. - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
  2. pthread_t threadId = NULL;
  3. // c字符串
  4. char *cString = "HelloCode";
  5. int result = pthread_create(&threadId, NULL, pthreadTest, cString);
  6. if (result == 0) {
  7. NSLog(@"成功");
  8. } else {
  9. NSLog(@"失败");
  10. }
  11. }
  12. void *pthreadTest(void *para){
  13. // 接 C 语言的字符串
  14. // NSLog(@"===> %@ %s", [NSThread currentThread], para);
  15. // __bridge 将 C 语言的类型桥接到 OC 的类型
  16. NSString *name = (__bridge NSString *)(para);
  17. NSLog(@"===>%@ %@", [NSThread currentThread], name);
  18. return NULL;
  19. }

使用pthread_create创建线程

参数:

  • pthread_t:要创建线程的结构体指针,通常开发的时候,如果遇到 C 语言的结构体,类型后缀 _t / Ref 结尾,同时不需要 *

  • 线程的属性,nil(空对象,OC使用的) ,NULL(空地址,C使用的)

  • 线程要执行的函数地址

    • void *:返回类型,表示指向任意对象的指针,和OC中的id类似

    • (*):函数名

    • (void *):参数类型,void *

  • 传递给第三个参数(函数)的参数


    返回值:

  • int类型

    • 0:创建线程成功
    • 0:创建线程失败的错误码,失败有多种可能

1.1 COC的桥接

  • __bridge只做类型转换,但是不修改对象(内存)管理权

  • __bridge_retained(也可以使用CFBridgingRetain)将Objective-C的对象转换为Core Foundation的对象,同时将对象(内存)的管理权交给我们,后续需要使用CFRelease或者相关方法来释放对象

  • __bridge_transfer(也可以使用CFBridgingRelease)将Core Foundation的对象转换为Objective-C的对象,同时将对象(内存)的管理权交给ARC

2. NSThread

NSthread是苹果官方提供面向对象的线程操作技术,是对thread的上层封装,比较偏向于底层。简单方便,可以直接操作线程对象,使用频率较少

创建线程的三种方式:

  • 通过init初始化方式创建,开辟线程,启动线程

  • detach分离,不需要启动,直接分离出新的线程执行

  • 隐式的多线程调用方法,没有thread,也没有start。所属NSObjectNSThreadPerformAdditions分类

  1. - (void)creatThreadMethod{
  2. NSLog(@"%@", [NSThread currentThread]);
  3. //方式一:
  4. NSThread *t = [[NSThread alloc] initWithTarget:self.p selector:@selector(study:) object:@100];
  5. t.name = @"学习线程";
  6. [t start];
  7. //方式二:
  8. [NSThread detachNewThreadSelector:@selector(study:) toTarget:self.p withObject:@10000];
  9. //方式三:
  10. [self.p performSelectorInBackground:@selector(study:) withObject:@5000];
  11. NSLog(@"%@", [NSThread currentThread]);
  12. }

2.1 属性

  • name:在应用程序中,收集错误日志,能够记录工作的线程。否则不好判断具体哪一个线程出的问题

  • stackSize:该值必须以字节为单位,且为4KB的倍数

  • isExecuting:线程是否在执行

  • isCancelled:线程是否被取消

  • isFinished:是否完成

  • isMainThread:是否是主线程

  • threadPriority:线程的优先级,取值范围0.0-1.0,默认优先级0.51.0表示最高优先级,优先级高CPU调度的频率高

  • qualityOfService:服务质量,替代threadPriority属性

  1. - (void)testThreadProperty{
  2. // 主线程 512K
  3. NSLog(@"NSThread:%@,stackSize:%zdK,isMainThread:%d", [NSThread currentThread], [NSThread currentThread].stackSize / 1024, [NSThread currentThread].isMainThread);
  4. NSThread *t = [[NSThread alloc] initWithTarget:self selector:@selector(eat) object:nil];
  5. t.name = @"吃饭线程";
  6. t.stackSize = 1024*1024;
  7. t.threadPriority = 1;
  8. [t start];
  9. }
  10. -------------------------
  11. //输出以下内容:
  12. NSThread:<NSThread: 0x281014600>{number = 1, name = main},stackSize512KisMainThread1

2.2 类方法

  • currentThread:获取当前线程

  • sleepForTimeInterval:阻塞线程

  • exit:退出线程

  • mainThread:获取主线程

  1. - (void)threadTest{
  2. //当前线程
  3. [NSThread currentThread];
  4. // 如果返回值为1,表示主线程,否则是子线程
  5. NSLog(@"%@", [NSThread currentThread]);
  6. //阻塞休眠
  7. [NSThread sleepForTimeInterval:2];//休眠时长,单位秒
  8. [NSThread sleepUntilDate:[NSDate date]];//休眠到指定时间
  9. //退出线程
  10. [NSThread exit];
  11. //判断当前线程是否为主线程
  12. [NSThread isMainThread];
  13. //判断当前线程是否是多线程
  14. [NSThread isMultiThreaded];
  15. //主线程的对象
  16. NSThread *mainThread = [NSThread mainThread];
  17. NSLog(@"%@", mainThread);
  18. }

2.3 exit & cancel

  • exit:一旦强行终止线程,后续的所有代码都不会执行

  • cancel:取消当前线程,但是不能取消正在执行的线程

  1. - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
  2. [self testThreadStatus];
  3. }
  4. - (void)testThreadStatus{
  5. NSLog(@"%d %d %d", self.t.isExecuting, self.t.isFinished, self.t.isCancelled);
  6. if ( self.t == nil || self.t.isCancelled || self.t.isFinished ) {
  7. self.t = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
  8. self.t.name = @"跑步线程";
  9. [self.t start];
  10. }else{
  11. NSLog(@"%@ 正在执行",self.t.name);
  12. [self.t cancel];
  13. self.t = nil;
  14. }
  15. }
  16. - (void)run{
  17. NSLog(@"开始");
  18. // 下面的代码的作用是判断线程状态,可能因为下面的延时,阻塞会带来当前线程的一些影响
  19. [NSThread sleepForTimeInterval:3];
  20. // 判断线程是否被取消
  21. if ([NSThread currentThread].isCancelled) {
  22. NSLog(@"%@被取消",self.t.name);
  23. return;
  24. }
  25. for (NSInteger i = 0; i < 10; i++) {
  26. // 判断线程是否被取消
  27. if ([NSThread currentThread].isCancelled) {
  28. NSLog(@"%@被取消",self.t.name);
  29. return;
  30. }
  31. if (i == 3) {
  32. // 睡指定的时长(秒)
  33. [NSThread sleepForTimeInterval:1];
  34. }
  35. NSLog(@"%@ %zd", [NSThread currentThread], i);
  36. // 内部取消线程
  37. // 强制退出 - 当某一个条件满足,不希望线程继续工作,直接杀死线程,退出
  38. if (i == 8) {
  39. // 强制退出当前所在线程!后续的所有代码都不会执行
  40. [NSThread exit];
  41. }
  42. }
  43. NSLog(@"完成");
  44. }

3. GCD

3.1 dispatch_after

dispatch_after:表示在某队列中的block延迟执行

  • 应用场景:在主队列上延迟执行一项任务,如viewDidload之后延迟1s,提示一个alertview(是延迟加入到队列,而不是延迟执行)
  1. - (void)testGCD{
  2. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  3. NSLog(@"2s后输出");
  4. });
  5. }

3.2 dispatch_once

dispatch_once:保证在App运行期间,block中的代码只执行一次

  • 应用场景:单例模式、Method Swizzling
  1. - (void)testGCD{
  2. static dispatch_once_t onceToken;
  3. dispatch_once(&onceToken, ^{
  4. ...
  5. });
  6. }

3.3 dispatch_apply

dispatch_apply:将指定的Block追加到指定的队列中重复执行,并等到全部的处理执行结束,相当于线程安全的循环

  • 应用场景:用来拉取网络数据后提前算出各个控件的大小,防止绘制时计算,提高表单滑动流畅性

    • 添加到串行队列中:按序执行

    • 添加到主队列中:死锁

    • 添加到并发队列中:乱序执行

    • 添加到全局队列中:乱序执行

  1. - (void)testGCD{
  2. dispatch_queue_t queue = dispatch_queue_create("testGCD", DISPATCH_QUEUE_SERIAL);
  3. NSLog(@"dispatch_apply前");
  4. dispatch_apply(10, queue, ^(size_t index) {
  5. NSLog(@"dispatch_apply 的线程 %zu - %@", index, [NSThread currentThread]);
  6. });
  7. NSLog(@"dispatch_apply后");
  8. }
  • 参数1:重复次数
  • 参数2:添加的队列
  • 参数3:任务Block

3.4 dispatch_group_t

dispatch_group_t:调度组将任务分组执行,能监听任务组完成,并设置等待时间

  • 应用场景:多个接口请求之后刷新页面
  1. - (void)testGCD{
  2. dispatch_group_t group = dispatch_group_create();
  3. dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
  4. dispatch_group_async(group, queue, ^{
  5. NSLog(@"接口1");
  6. });
  7. dispatch_group_async(group, queue, ^{
  8. NSLog(@"接口2");
  9. });
  10. dispatch_group_notify(group, dispatch_get_main_queue(), ^{
  11. NSLog(@"刷新");
  12. });
  13. }
  • dispatch_group_create:创建一个调度任务组

  • dispatch_group_async:把一个任务异步提交到任务组里

3.4.1 dispatch_group_enter & dispatch_group_leave

dispatch_group_enterdispatch_group_leave成对出现,使进出组的逻辑更加清晰

  • 这种方式用在不使用dispatch_group_async来提交任务,且必须配合使用
  1. - (void)testGCD{
  2. dispatch_group_t group = dispatch_group_create();
  3. dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
  4. dispatch_group_enter(group);
  5. dispatch_async(queue, ^{
  6. NSLog(@"接口1");
  7. dispatch_group_leave(group);
  8. });
  9. dispatch_group_enter(group);
  10. dispatch_async(queue, ^{
  11. NSLog(@"接口2");
  12. dispatch_group_leave(group);
  13. });
  14. dispatch_group_notify(group, dispatch_get_main_queue(), ^{
  15. NSLog(@"刷新");
  16. });
  17. }

3.4.2 dispatch_group_wait

dispatch_group_wait:设置等待时间

  • 在等待时间结束后,如果还没有执行完任务组,则返回。返回0代表执行成功,非0则执行失败
  1. - (void)testGCD{
  2. dispatch_group_t group = dispatch_group_create();
  3. dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
  4. dispatch_group_enter(group);
  5. dispatch_async(queue, ^{
  6. NSLog(@"接口1");
  7. dispatch_group_leave(group);
  8. });
  9. dispatch_group_enter(group);
  10. dispatch_async(queue, ^{
  11. NSLog(@"接口2");
  12. dispatch_group_leave(group);
  13. });
  14. // long timeout = dispatch_group_wait(group, DISPATCH_TIME_NOW);
  15. // long timeout = dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
  16. long timeout = dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, 30 * NSEC_PER_SEC));
  17. if (timeout == 0) {
  18. NSLog(@"完成");
  19. }else{
  20. NSLog(@"超时");
  21. }
  22. dispatch_group_notify(group, dispatch_get_main_queue(), ^{
  23. NSLog(@"刷新");
  24. });
  25. }

参数:

  • group:需要等待的调度组

  • timeout:等待的超时时间(即等多久)

    • DISPATCH_TIME_NOW:不等待,直接判定调度组是否执行完毕

    • DISPATCH_TIME_FOREVER:阻塞当前调度组,直到调度组执行完毕

返回值:

  • long类型

    • 0:在指定时间内调度组完成了任务

    • 0:在指定时间内调度组没有按时完成任务

3.5 dispatch_barrier_async

dispatch_barrier_async:先执行栅栏前任务,再执行栅栏任务,最后执行栅栏后任务

  • 应用场景:无需等待栅栏执行完,会继续往下走
  1. - (void)testGCD{
  2. dispatch_queue_t queue = dispatch_queue_create("testGCD", DISPATCH_QUEUE_CONCURRENT);
  3. NSLog(@"逻辑1 - %@", [NSThread currentThread]);
  4. dispatch_async(queue, ^{
  5. sleep(2);
  6. NSLog(@"接口1 - %@", [NSThread currentThread]);
  7. });
  8. NSLog(@"逻辑2 - %@", [NSThread currentThread]);
  9. dispatch_barrier_async(queue, ^{
  10. NSLog(@"栅栏 - %@", [NSThread currentThread]);
  11. });
  12. NSLog(@"逻辑3 - %@", [NSThread currentThread]);
  13. dispatch_async(queue, ^{
  14. sleep(2);
  15. NSLog(@"接口2 - %@", [NSThread currentThread]);
  16. });
  17. NSLog(@"逻辑4 - %@", [NSThread currentThread]);
  18. }
  19. -------------------------
  20. //输出以下内容:
  21. 逻辑1 - <NSThread: 0x280c2c940>{number = 1, name = main}
  22. 逻辑2 - <NSThread: 0x280c2c940>{number = 1, name = main}
  23. 逻辑3 - <NSThread: 0x280c2c940>{number = 1, name = main}
  24. 逻辑4 - <NSThread: 0x280c2c940>{number = 1, name = main}
  25. 接口1 - <NSThread: 0x280c64080>{number = 8, name = (null)}
  26. 栅栏 - <NSThread: 0x280c64080>{number = 8, name = (null)}
  27. 接口2 - <NSThread: 0x280c64080>{number = 8, name = (null)}

3.6 dispatch_barrier_sync

dispatch_barrier_sync:和dispatch_barrier_async作用相同,但会堵塞线程,影响后面的任务执行

  • 需要等待栅栏执行完,才会执行栅栏后面的任务,慎用
  1. - (void)testGCD{
  2. dispatch_queue_t queue = dispatch_queue_create("testGCD", DISPATCH_QUEUE_CONCURRENT);
  3. NSLog(@"逻辑1 - %@", [NSThread currentThread]);
  4. dispatch_async(queue, ^{
  5. sleep(2);
  6. NSLog(@"接口1 - %@", [NSThread currentThread]);
  7. });
  8. NSLog(@"逻辑2 - %@", [NSThread currentThread]);
  9. dispatch_barrier_sync(queue, ^{
  10. NSLog(@"栅栏 - %@", [NSThread currentThread]);
  11. });
  12. NSLog(@"逻辑3 - %@", [NSThread currentThread]);
  13. dispatch_async(queue, ^{
  14. sleep(2);
  15. NSLog(@"接口2 - %@", [NSThread currentThread]);
  16. });
  17. NSLog(@"逻辑4 - %@", [NSThread currentThread]);
  18. }
  19. -------------------------
  20. //输出以下内容:
  21. 逻辑1 - <NSThread: 0x281078980>{number = 1, name = main}
  22. 逻辑2 - <NSThread: 0x281078980>{number = 1, name = main}
  23. 接口1 - <NSThread: 0x281038380>{number = 5, name = (null)}
  24. 栅栏 - <NSThread: 0x281078980>{number = 1, name = main}
  25. 逻辑3 - <NSThread: 0x281078980>{number = 1, name = main}
  26. 逻辑4 - <NSThread: 0x281078980>{number = 1, name = main}
  27. 接口2 - <NSThread: 0x281057500>{number = 9, name = (null)}

3.7 dispatch_semaphore_t

dispatch_semaphore_t:信号量

  • 应用场景:用作同步锁,用于控制GCD最大并发数
  1. - (void)testGCD{
  2. dispatch_queue_t queue = dispatch_queue_create("testGCD", DISPATCH_QUEUE_CONCURRENT);
  3. for (int i = 0; i < 10; i++) {
  4. dispatch_async(queue, ^{
  5. sleep(1);
  6. NSLog(@"当前 - %d, 线程 - %@", i, [NSThread currentThread]);
  7. });
  8. }
  9. dispatch_semaphore_t sem = dispatch_semaphore_create(0);
  10. for (int i = 0; i < 10; i++) {
  11. dispatch_async(queue, ^{
  12. sleep(1);
  13. NSLog(@"当前 - %d, 线程 - %@", i, [NSThread currentThread]);
  14. dispatch_semaphore_signal(sem);
  15. });
  16. dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
  17. }
  18. NSLog(@"完成");
  19. }
  • dispatch_semaphore_create:创建信号量

  • dispatch_semaphore_wait:等待信号量,信号量减1。当信号量< 0时会阻塞当前线程,根据传入的等待时间决定接下来的操作。如果永久等待将等到信号signal才执行下去

  • dispatch_semaphore_signal:释放信号量,信号量加1。当信号量>= 0会执行wait之后的代码

3.8 dispatch_source_t

iOS中一般使用NSTimer来处理定时逻辑,但NSTimer是依赖Runloop的,而Runloop可以运行在不同的模式下。如果NSTimer添加在一种模式下,当Runloop运行在其他模式下的时候,定时器会处于挂起状态。如果Runloop在阻塞状态,NSTimer触发时间就会推迟到下一个Runloop周期。因此NSTimer在计时上会有误差,并不是特别精确,而GCD定时器不依赖Runloop,计时精度要高很多

dispatch_source_t:用于计时操作,它创建的timer不依赖于RunLoop,计时精准度比NSTimer

  • 应用场景:GCDTimer
  1. static dispatch_source_t timer;
  2. - (void)testGCD{
  3. //1.创建队列
  4. dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
  5. //2.创建timer
  6. timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
  7. //3.设置timer首次执行时间,间隔,精确度
  8. dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 2.0 * NSEC_PER_SEC, 0.1 * NSEC_PER_SEC);
  9. //4.设置timer事件回调
  10. dispatch_source_set_event_handler(timer, ^{
  11. NSLog(@"计时");
  12. });
  13. //5.默认是挂起状态,需要手动激活
  14. dispatch_resume(timer);
  15. }

dispatch_source:一种基本的数据类型,可以用来监听一些底层的系统事件

  • Timer Dispatch Source:定时器事件源,用来生成周期性的通知或回调

  • Signal Dispatch Source:监听信号事件源,当有UNIX信号发生时会通知

  • Descriptor Dispatch Source:监听文件或socket事件源,当文件或socket数据发生变化时会通知

  • Process Dispatch Source:监听进程事件源,与进程相关的事件通知

  • Mach port Dispatch Source:监听Mach端口事件源

  • Custom Dispatch Source:监听自定义事件源

常用API

  • dispatch_source_create: 创建事件源

  • dispatch_source_set_event_handler: 设置数据源回调

  • dispatch_source_merge_data: 设置事件源数据

  • dispatch_source_get_data: 获取事件源数据

  • dispatch_resume: 继续

  • dispatch_suspend: 挂起

  • dispatch_cancle: 取消

4. NSOperation

NSOperation是基于GCD之上的更高一层封装,NSOperation需要配合NSOperationQueue来实现多线程

实现多线程的步骤:

  • 创建任务:先将需要执行的操作封装到NSOperation对象中

  • 创建队列:创建NSOperationQueue

  • 将任务加入到队列中:将NSOperation对象添加到NSOperationQueue

  1. - (void)testNSOperation{
  2. //处理事务
  3. NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(handleInvocation:) object:@"testNSOperation"];
  4. //创建队列
  5. NSOperationQueue *queue = [[NSOperationQueue alloc] init];
  6. //操作加入队列
  7. [queue addOperation:op];
  8. }
  9. - (void)handleInvocation:(id)operation{
  10. NSLog(@"%@ - %@", operation, [NSThread currentThread]);
  11. }

NSOperation是抽象类,开发中实际用到的是它的子类:

  • NSInvocationOperation

  • NSBlockOperation

  • 自定义子类

4.1 NSInvocationOperation

  1. - (void)testNSOperation{
  2. NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(handleInvocation:) object:@"testNSOperation"];
  3. [invocationOperation start];
  4. }

4.2 NSBlockOperation

  1. - (void)testNSOperation{
  2. NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
  3. NSLog(@"main task:%@", [NSThread currentThread]);
  4. }];
  5. [blockOperation addExecutionBlock:^{
  6. NSLog(@"task1:%@", [NSThread currentThread]);
  7. }];
  8. [blockOperation addExecutionBlock:^{
  9. NSLog(@"task2:%@", [NSThread currentThread]);
  10. }];
  11. [blockOperation addExecutionBlock:^{
  12. NSLog(@"task3:%@", [NSThread currentThread]);
  13. }];
  14. [blockOperation start];
  15. }
  • 通过addExecutionBlock方法,可以让NSBlockOperation实现多线程

  • NSBlockOperation创建block中的任务是在主线程执行,而使用addExecutionBlock加入的任务是在子线程执行

4.3 自定义子类

  1. @interface LGOperation : NSOperation
  2. @end
  3. @implementation LGOperation
  4. - (void)main{
  5. for (int i = 0; i < 3; i++) {
  6. NSLog(@"NSOperation的子类:%@",[NSThread currentThread]);
  7. }
  8. }
  9. @end
  10. - (void)testNSOperation{
  11. LGOperation *operation = [[LGOperation alloc] init];
  12. [operation start];
  13. }
  • 使用NSOperation的子类,重写它的main方法

4.4 NSOperationQueue

NSOperationQueue包含两种队列:

  • 主队列:主队列上的任务是在主线程执行的

  • 其他队列:包含串行和并发队列,加入到非主队列中的任务,默认就是并发,开启多线程

  1. - (void)testNSOperation{
  2. // 初始化添加事务
  3. NSBlockOperation *bo = [NSBlockOperation blockOperationWithBlock:^{
  4. NSLog(@"任务1:%@",[NSThread currentThread]);
  5. }];
  6. // 添加事务
  7. [bo addExecutionBlock:^{
  8. NSLog(@"任务2:%@",[NSThread currentThread]);
  9. }];
  10. // 回调监听
  11. bo.completionBlock = ^{
  12. NSLog(@"完成");
  13. };
  14. NSOperationQueue *queue = [[NSOperationQueue alloc] init];
  15. [queue addOperation:bo];
  16. NSLog(@"事务添加进了NSOperationQueue");
  17. }
  • NSInvocationOperationNSBlockOperation的区别:

    • NSInvocationOperation类似于target形式

    • NSBlockOperation类似于block形式。函数式编程,业务逻辑代码可读性更高

4.4.1 执行顺序

  1. - (void)testNSOperation{
  2. NSOperationQueue *queue = [[NSOperationQueue alloc] init];
  3. for (int i = 0; i < 5; i++) {
  4. [queue addOperationWithBlock:^{
  5. NSLog(@"%@---%d", [NSThread currentThread], i);
  6. }];
  7. }
  8. }

4.4.2 优先级

  1. - (void)testNSOperation{
  2. NSBlockOperation *bo1 = [NSBlockOperation blockOperationWithBlock:^{
  3. for (int i = 0; i < 5; i++) {
  4. NSLog(@"第一个操作 %d --- %@", i, [NSThread currentThread]);
  5. }
  6. }];
  7. // 设置最高优先级
  8. bo1.qualityOfService = NSQualityOfServiceUserInteractive;
  9. NSBlockOperation *bo2 = [NSBlockOperation blockOperationWithBlock:^{
  10. for (int i = 0; i < 5; i++) {
  11. NSLog(@"第二个操作 %d --- %@", i, [NSThread currentThread]);
  12. }
  13. }];
  14. // 设置最低优先级
  15. bo2.qualityOfService = NSQualityOfServiceBackground;
  16. NSOperationQueue *queue = [[NSOperationQueue alloc] init];
  17. [queue addOperation:bo1];
  18. [queue addOperation:bo2];
  19. }

4.4.3 并发数

  1. - (void)testNSOperation{
  2. NSOperationQueue *queue = [[NSOperationQueue alloc] init];
  3. queue.name = @"Felix";
  4. queue.maxConcurrentOperationCount = 2;
  5. for (int i = 0; i < 5; i++) {
  6. [queue addOperationWithBlock:^{
  7. [NSThread sleepForTimeInterval:2];
  8. NSLog(@"%d-%@",i,[NSThread currentThread]);
  9. }];
  10. }
  11. }
  • GCD中只能使用信号量来设置并发数,而NSOperation使用maxConcurrentOperationCount就能设置并发数

4.4.4 添加依赖

  1. - (void)testNSOperation{
  2. NSOperationQueue *queue = [[NSOperationQueue alloc] init];
  3. NSBlockOperation *bo1 = [NSBlockOperation blockOperationWithBlock:^{
  4. [NSThread sleepForTimeInterval:0.5];
  5. NSLog(@"获取用户id");
  6. }];
  7. NSBlockOperation *bo2 = [NSBlockOperation blockOperationWithBlock:^{
  8. [NSThread sleepForTimeInterval:0.5];
  9. NSLog(@"通过用户id,获取用户对象");
  10. }];
  11. NSBlockOperation *bo3 = [NSBlockOperation blockOperationWithBlock:^{
  12. [NSThread sleepForTimeInterval:0.5];
  13. NSLog(@"通过用户对象,获取文章列表");
  14. }];
  15. [bo2 addDependency:bo1];
  16. [bo3 addDependency:bo2];
  17. [queue addOperations:@[bo1,bo2,bo3] waitUntilFinished:YES];
  18. NSLog(@"完成");
  19. }

4.4.5 线程间通讯

  1. - (void)testNSOperation{
  2. NSOperationQueue *queue = [[NSOperationQueue alloc] init];
  3. queue.name = @"test";
  4. [queue addOperationWithBlock:^{
  5. NSLog(@"接口请求:%@--%@", [NSOperationQueue currentQueue], [NSThread currentThread]);
  6. [[NSOperationQueue mainQueue] addOperationWithBlock:^{
  7. NSLog(@"刷新:%@--%@", [NSOperationQueue currentQueue], [NSThread currentThread]);
  8. }];
  9. }];
  10. }