1、为什么用runloop
一般来讲,一个线程一次只能执行一个任务,执行完成后线程就会退出。
如果我们需要一个机制,让线程能随时处理事件但并不退出,这种模型通常被称作 。
RunLoop 实际上就是一个对象,这个对象管理了其需要处理的事件和消息,
线程执行了这个函数后,就会一直处于这个函数内部 “接受消息->等待->处理” 的循环中,直到这个循环结束(比如传入 quit 的消息),函数返回。
2、runloop创建方式
CFRunLoop 是基于 pthread 来管理的。
线程和 RunLoop 之间是一一对应的,其关系是保存在一个全局的 Dictionary 里。
- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay inModes:(NSArray<NSRunLoopMode> *)modes;//将一个timer事件加入1个或者多个mode中
PerformSelecter
当调用 NSObject 的 performSelecter:afterDelay: 后,实际上其内部会创建一个 Timer 并添加到当前线程的 RunLoop 中。所以如果当前线程没有 RunLoop,则这个方法会失效。
当调用 performSelector:onThread: 时,实际上其会创建一个source0 加到对应的线程去,同样的,如果对应线程没有 RunLoop 该方法也会失效。
定时异步回调:
用runloop的observer,每次进入到beforeWating的时候调用block
- (BOOL)runUntilBlock:(BOOL(^)())block timeout:(NSTimeInterval)timeout{
__block Boolean fulfilled = NO;
void(^beforeWaiting)(CFRunLoopObserverRef observer,CFRunLoopActivity activity) = ^(CFRunLoopObserverRef observer,CFRunLoopActivity activity) {
fulfilled = block();
if (fulfilled) {
CFRunLoopStop(CRRunLoopGetCurrent());
}
};
CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(NULL, CFRunLoopBeforeWaiting,true,0,beforeWating);
CFRunLoopAddObserver(CFRunLoopGetCurrent(),observer,KCFRunLoopDefaultMode);
CFRunLoopRunInMode(kCFRunLoopDefaultMode,timeout,false);
CFRunLoopRemoveObserver(CFRunLoopGetCurrent(),observer,KCFRunLoopDefaultMode);
CFRelease(observer);
return fulfilled;
}
runloop和dispatch的联系:runloop会在周期内询问dispatch主队列是否有任务(即block块代码)需要完成,并当作event实践处理
runloop有一个timer,但和diapacth的timer不一样,场景有(NSTimer,performSelector: after)
runloop和autoreleasePool联系:autorealeasePool块执行完成,回调用autoReleasePoolPage pop方法,在runloop的beforeWating和afterWating之间执行此方法,执行release操作