RunLoop
是經過內部維護的事件循環(Event Loop)
來對事件/消息
進行管理的一個對象main
函數不會退出int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
複製代碼
UIApplicationMain
內部默認開啓了主線程的RunLoop
,並執行了一段無限循環的代碼(不是簡單的for循環
或while循環
)UIApplicationMain
函數一直沒有返回,不斷地接收處理消息以及等待休眠,因此運行程序以後,會保持持續運行狀態git
Source1
: 基於Port
的線程間通訊Source0
: 觸摸事件、PerformSelector
Timer
: 定時器Observer
: 監聽器,用於監聽RunLoop
的狀態RunLoop
是一一對應的,其映射關係是保存在一個全局的Dictionary
裏,線程做爲key
,RunLoop
做爲value
RunLoop
的runloop
在第一次獲取時被建立,在線程結束時被銷燬runloop
在程序一啓動就默認建立好了runloop
是懶加載的,只有當咱們使用的時候纔會建立,因此在子線程用定時器要注意:確保子線程的runloop
被建立,否則定時器不會回調RunLoop
(第一次調用[NSRunLoop currentRunLoop]
方法時,實際是會先去建立一個RunLoop
)RunLoop
中添加一個Port/Source
等維持RunLoop
的事件循環(若是RunLoop
的mode
中一個item
都沒有,RunLoop
會退出)RunLoop
@autoreleasepool {
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
[runLoop run];
}
複製代碼
NSLog(@"1");
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"2");
[self performSelector:@selector(test) withObject:nil afterDelay:10];
NSLog(@"3");
});
NSLog(@"4");
- (void)test{
NSLog(@"5");
}
複製代碼
答案是1423
,test
方法並不會執行 緣由是:若是是帶afterDelay
的延時函數,會在內部建立一個NSTimer
,而後添加到當前線程的RunLoop
中,也就是若是當前線程沒有開啓RunLoop
,該方法會失效 那麼咱們改爲:github
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"2");
[[NSRunLoop currentRunLoop] run];
[self performSelector:@selector(test) withObject:nil afterDelay:10];
NSLog(@"3");
});
複製代碼
test
方法依然不執行 緣由是:若是RunLoop
的mode
中一個item
都沒有,RunLoop
會退出 即在調用RunLoop
的run
方法後,因爲其mode
中沒有添加任何item
去維持RunLoop
的事件循環,RunLoop
隨即仍是會退出,因此咱們本身啓動RunLoop
,必定要在添加item
後bash
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"2");
[self performSelector:@selector(test) withObject:nil afterDelay:10];
[[NSRunLoop currentRunLoop] run];
NSLog(@"3");
});
複製代碼
附:個人博客地址async