线程创建出来就处于等待状态(有或无任务),想用它的时候就用它执行任务,不想用的时候就处于等待状态。

  • 聊天发送语音消息,可能会专门开一个子线程来处理;
  • 在后台记录用户的停留时间或某个按钮点击次数,这些用主线程做可能不太方便,可能会开启一个子线程后台默默收集;

实现一个常驻线程

  • 为当前线程开启一个 Runloop
  • 向该Runloop中添加一个 Port/Source 等维持 Runloop 的事件循环
  • 启动该 Runloop
  1. #import "ViewController.h"
  2. @interface ViewController ()
  3. @property(nonatomic,strong)NSThread *thread;
  4. @end
  5. @implementation ViewController
  6. - (void)viewDidLoad {
  7. [super viewDidLoad];
  8. }
  9. -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
  10. {
  11. // 创建子线程并开启
  12. NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(show) object:nil];
  13. self.thread = thread;
  14. [thread start];
  15. }
  16. -(void)show
  17. {
  18. // 注意:打印方法一定要在RunLoop创建开始运行之前,如果在RunLoop跑起来之后打印,RunLoop先运行起来,已经在跑圈了就出不来了,进入死循环也就无法执行后面的操作了。
  19. // 但是此时点击Button还是有操作的,因为Button是在RunLoop跑起来之后加入到子线程的,当Button加入到子线程RunLoop就会跑起来
  20. NSLog(@"%s",__func__);
  21. // 1.创建子线程相关的RunLoop,在子线程中创建即可,并且RunLoop中要至少有一个Timer 或 一个Source 保证RunLoop不会因为空转而退出,因此在创建的时候直接加入
  22. // 添加Source [NSMachPort port] 添加一个端口
  23. [[NSRunLoop currentRunLoop] addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
  24. // 添加一个Timer
  25. NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(test) userInfo:nil repeats:YES];
  26. [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
  27. //创建监听者
  28. CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
  29. switch (activity) {
  30. case kCFRunLoopEntry:
  31. NSLog(@"RunLoop进入");
  32. break;
  33. case kCFRunLoopBeforeTimers:
  34. NSLog(@"RunLoop要处理Timers了");
  35. break;
  36. case kCFRunLoopBeforeSources:
  37. NSLog(@"RunLoop要处理Sources了");
  38. break;
  39. case kCFRunLoopBeforeWaiting:
  40. NSLog(@"RunLoop要休息了");
  41. break;
  42. case kCFRunLoopAfterWaiting:
  43. NSLog(@"RunLoop醒来了");
  44. break;
  45. case kCFRunLoopExit:
  46. NSLog(@"RunLoop退出了");
  47. break;
  48. default:
  49. break;
  50. }
  51. });
  52. // 给RunLoop添加监听者
  53. CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);
  54. // 2.子线程需要开启RunLoop
  55. [[NSRunLoop currentRunLoop]run];
  56. CFRelease(observer);
  57. }
  58. - (IBAction)btnClick:(id)sender {
  59. [self performSelector:@selector(test) onThread:self.thread withObject:nil waitUntilDone:NO];
  60. }
  61. -(void)test
  62. {
  63. NSLog(@"%@",[NSThread currentThread]);
  64. }
  65. @end

注意:创建子线程相关的RunLoop,在子线程中创建即可,并且RunLoop中要至少有一个Timer 或 一个Source 保证RunLoop不会因为空转而退出,因此在创建的时候直接加入,如果没有加入Timer或者Source,或者只加入一个监听者,运行程序会崩溃