iOS RunLoop与NSTimer RunLoop与多线程

返回上级目录:iOS面试专题一

文章目录

1.RunLoop与NSTimer

  • 我们的线程,或tableView,正常情况下是运行在default模式下。当我们对tableView进行滑动的时候,会进行一个Mode的切换,会切换到Tracking模式上。多个mode是为了对timer/observer/source进行一个隔离。 timer默认添加到default模式,这个时候如果切换打Tracking模式,定时器就不会在生效了
    iOS RunLoop与NSTimer RunLoop与多线程

1.1 CFRunLoopAddTimer源码分析

源码下载地址:https://opensource.apple.com/tarballs/CF/CF-855.17.tar.gz

  • commonMode是把一些mode打上mode的标记,可以把timer等同步到多个mode中
    iOS RunLoop与NSTimer RunLoop与多线程
    iOS RunLoop与NSTimer RunLoop与多线程
    iOS RunLoop与NSTimer RunLoop与多线程
    iOS RunLoop与NSTimer RunLoop与多线程
    iOS RunLoop与NSTimer RunLoop与多线程

2.RunLoop与多线程

  • 线程与RunLoop是什么关系
  • 自己创建的线程需要自己手动创建RunLoop
    iOS RunLoop与NSTimer RunLoop与多线程

2.1 怎样实现一个常驻线程

  • CFERunLoopGetCurrent(),这个方法本身,如果当前线程没有RunLoop,系统会为我们创建
  • RunLoop如果没有事件源需要处理的话,默认情况下,他是不能维持自己事件循环的,就会直接退出了。所以我们需要给他添加一个Port或者Source来维持他的事件循环机制
    iOS RunLoop与NSTimer RunLoop与多线程

2.1.1 实例代码MCObject.m

  • 在while循环中,可能会进入休眠状态
#import "MCObject.h"

@implementation MCObject

static NSThread *thread = nil;
// 标记是否要继续事件循环
static BOOL runAlways = YES;

+ (NSThread *)threadForDispatch{
    if (thread == nil) {
        @synchronized(self) {
            if (thread == nil) {
                // 线程的创建
                thread = [[NSThread alloc] initWithTarget:self selector:@selector(runRequest) object:nil];
                [thread setName:@"com.imooc.thread"];
                //启动
                [thread start];
            }
        }
    }
    return thread;
}

+ (void)runRequest
{
    // 创建一个Source
    CFRunLoopSourceContext context = {0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
    CFRunLoopSourceRef source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context);
    
    // 创建RunLoop,同时向RunLoop的DefaultMode下面添加Source
    CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
    
    // 如果可以运行
    while (runAlways) {
        @autoreleasepool {
            // 令当前RunLoop运行在DefaultMode下面,第二个参数,运行到指定事件结束,1.0e10为无穷大。第三个参数,资源被处理后是否返回
            CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1.0e10, true);
        }
    }
    
    // 某一时机 静态变量runAlways = NO时 可以保证跳出RunLoop,线程退出。source移除后,runloop会退出
    CFRunLoopRemoveSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
    CFRelease(source);
}

@end
上一篇:使用 KVO 可能会拖慢启动速度


下一篇:NSTimer、performSelector 函数没有被调用的原因