[关闭]
@whiteiOS 2017-02-23T04:16:09.000000Z 字数 6711 阅读 772

八、RunLoop

多线程网络


(一)基本作用

1. 保持程序的持续运行

  1. int main(int argc, char * argv[]) {
  2. @autoreleasepool {
  3. return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
  4. }
  5. }
  1. int main(int argc, char * argv[]) {
  2. @autoreleasepool {
  3. NSLog(@"%s", __func__);
  4. int number = UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
  5. NSLog(@"%d", number);
  6. return number;
  7. }
  8. }

2. 处理APP中的各种事件

3. 节省CPU资源,提供程序性能

(二)RunLoop与线程的关系

  1. //创建子线程对应的RunLoop,currentRunLoop是懒加载的
  2. //该方法既能创建子线程的RunLoop,也能获取子线程的RunLoop
  3. NSRunLoop *currentRunloop = [NSRunLoop currentRunLoop];
  4. //子线程的RunLoop还必须手动开启
  5. [currentRunloop run];

(三)RunLoop对象

  1. //获取主线程的RunLoop对象
  2. [NSRunLoop mainRunLoop];
  3. //获取当前线程的RunLoop对象
  4. [NSRunLoop currentRunLoop];
  1. //获取主线程的RunLoop对象
  2. CFRunLoopGetMain();
  3. //获取当前线程的RunLoop对象
  4. CFRunLoopGetCurrent();

(四)RunLoop相关类

1. CFRunLoopModeRef

(1) 介绍
  1. //默认Mode,通常主线程是在这个Mode下运行
  2. kCFRunLoopDefaultMode;
  3. //界面追踪Mode,用于ScrollView追踪触摸滑动,保证界面滑动时不受其他Mode影响
  4. //如果界面在滑动scrollView或者tableView或者textView等,会自动进入该模式
  5. UITrackingRunLoopMode;
  6. //在刚启动APP时进入的第一个Mode,启动完成后就不在使用
  7. UIInitializationRunLoopMode;
  8. //接受系统时间的内部Mode,通常用不到
  9. GSEventReceiveRunLoopMode;
  10. //这个一个占位用的Mode,不是一种真正的Mode
  11. kCFRunLoopCommonModes;
(2) NSTimer和运行模式结合使用

①情况一:使用timerWithTimeInterval:创建NSTimer

  1. NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(test) userInfo:nil repeats:YES];
  2. [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];

②情况二:使用timerWithTimeInterval:创建NSTimer,并且在界面添加一个tableView控件

注意:NSRunLoopCommonModes并不是一种真正的运行模式,它类似于一个标签,而UITrackingRunLoopModeNSDefaultRunLoopMode这两种运行模式都带有NSRunLoopCommonModes这个标签。怎么验证呢?通过打印当前的RunLoop对象,如下图。凡是添加到NSRunLoopCommonModes中的事件都会同时添加到带有common标签的运行模式上,所以定时器才会在两种模式下都能正常运行

③情况三:使用scheduledTimerWithTimeInterval:创建定时器

  1. [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(test) userInfo:nil repeats:YES];

由此可见,NSTimer依赖于RunLoop的运行模式;另外,如果在子线程中直接创建NSTimer是不行的,因为NSTimer要添加到当前的RunLoop中,而在子线程中默认情况下是不存在RunLoop的,还需要自己创建子线程的RunLoop

(3) GCD中的定时器

  1. - (void)GCDTimer
  2. {
  3. /*
  4. 作用:1.创建GCD中的定时器
  5. 参数一:DISPATCH_SOURCE_TYPE_TIMER说明是定时器
  6. 参数二:描述信息
  7. 参数三:更详细的描述信息
  8. 参数四:队列,决定GCD定时器的任务在哪个线程中执行
  9. */
  10. dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));
  11. /*
  12. 作用:2.设置定时器
  13. 参数一:timer-定时器对象
  14. 参数二:起始时间,DISPATCH_TIME_NOW-从现在开始计时
  15. 参数三:间隔时间(GCD中的时间单位为纳秒)
  16. 参数四:精准度,0表示绝对精准
  17. */
  18. dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 2.0 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
  19. //3.设置定时器执行的任务
  20. dispatch_source_set_event_handler(timer, ^{
  21. NSLog(@"%@", [NSThread currentThread]);
  22. });
  23. //4.启动执行
  24. dispatch_resume(timer);
  25. //5.此时定时器还不会启动,因为timer只是局部变量,当2秒后开始执行的时候可能timer已经被释放掉了,所以需要添加一个属性对timer进行强引用
  26. self.timer = timer;
  27. }
  28. @property (nonatomic, strong) dispatch_source_t timer;

2. CFRunLoopSourceRef

3. CFRunLoopTimerRef

4. CFRunLoopObserverRef

  1. - (void)runLoopObserver
  2. {
  3. /*
  4. 作用:1.创建监听者
  5. 参数一:怎么分配内存空间
  6. 参数二:要监听的RunLoop的状态
  7. 参数三:是否持续监听
  8. 参数四:优先级,总是传0
  9. 参数五:当状态改变时候的回调
  10. */
  11. CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
  12. /*
  13. RunLoop的所有状态
  14. kCFRunLoopEntry = (1UL << 0), 即将进入RunLoop
  15. kCFRunLoopBeforeTimers = (1UL << 1), 即将处理timer事件
  16. kCFRunLoopBeforeSources = (1UL << 2), 即将处理source事件
  17. kCFRunLoopBeforeWaiting = (1UL << 5), 即将进入睡眠
  18. kCFRunLoopAfterWaiting = (1UL << 6), 被唤醒
  19. kCFRunLoopExit = (1UL << 7), RunLoop退出
  20. kCFRunLoopAllActivities = 0x0FFFFFFFU RunLoop所有状态
  21. */
  22. switch (activity) {
  23. case kCFRunLoopEntry:
  24. NSLog(@"即将进入RunLoop");
  25. break;
  26. case kCFRunLoopBeforeTimers:
  27. NSLog(@"即将处理timer事件");
  28. break;
  29. case kCFRunLoopBeforeSources:
  30. NSLog(@"即将处理source事件");
  31. break;
  32. case kCFRunLoopBeforeWaiting:
  33. NSLog(@"即将进入睡眠");
  34. break;
  35. case kCFRunLoopAfterWaiting:
  36. NSLog(@"被唤醒");
  37. break;
  38. case kCFRunLoopExit:
  39. NSLog(@"RunLoop退出");
  40. break;
  41. default:
  42. break;
  43. }
  44. });
  45. /*
  46. 作用:2.把观察者添加到RunLoop上
  47. 参数一:要监听哪个RunLoop
  48. 参数二:观察者
  49. 参数三:运行模式
  50. */
  51. CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);
  52. }

(五)RunLoop运行逻辑

(六)RunLoop具体应用

1. NSTimer

2. 常驻线程

  1. @interface ViewController ()
  2. /** 注释 */
  3. @property (nonatomic, strong) NSThread *thread;
  4. @end
  5. //按钮一:创建子线程
  6. - (IBAction)createThread
  7. {
  8. self.thread = [[NSThread alloc] initWithTarget:self selector:@selector(task1) object:nil];
  9. [self.thread start];
  10. }
  11. - (void)task1
  12. {
  13. NSLog(@"task1---%@",[NSThread currentThread]);
  14. }
  15. //按钮二:让刚才子线程继续工作
  16. - (IBAction)goOnWorking
  17. {
  18. [self performSelector:@selector(task2) onThread:self.thread withObject:nil waitUntilDone:YES];
  19. }
  20. - (void)task2
  21. {
  22. NSLog(@"task2---%@",[NSThread currentThread]);
  23. }
  1. - (void)task1
  2. {
  3. //1.获得子线程对应的RunLoop
  4. NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
  5. //2.开启RunLoop
  6. [runLoop run];
  7. }
  1. - (void)task1
  2. {
  3. //1.获得子线程对应的RunLoop
  4. NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
  5. //2.给RunLoop添加source
  6. [runLoop addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
  7. //3.开启RunLoop
  8. [runLoop run];
  9. }

3.自动释放池

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注