Run Loop
- Run Loop是事件驅(qū)動(dòng)的。
- iOS中有2套API來訪問使用Run Loop
- Foundation(OC語言)
- NSRun Loop(對CFRun LoopREF的封裝)
- Core Foundation(C語言)
- CFRun LoopREF
- Foundation(OC語言)
Run Loop與線程
- 每條線程都有唯一的Run Loop對象與之對應(yīng)懂算。
- 主線程的Run Loop會自動(dòng)創(chuàng)建,子線程的Run Loop需要手動(dòng)創(chuàng)建穗慕。
- Run Loop在第一次獲取時(shí)創(chuàng)建,在線程結(jié)束時(shí)銷毀妻导。
獲取Run Loop對象
-
獲取當(dāng)前線程的Run Loop對象
//Foundation [NSRun Loop currentRun Loop]; //Core Foundation CFRun LoopGetCurrent();
獲取主線程Run Loop
//Foundation
[NSRun Loop mainRun Loop];
//Core Foundation
CFRun LoopGetMain();
Run Loop相關(guān)類
CFRun LoopRef
CFRun LoopModeRef
CFRun LoopSourceRef
CFRun LoopTimerRef
CFRun LoopObserverRef
- 一個(gè) Run Loop 包含若干個(gè)Mode逛绵,每個(gè)Mode中包含若干個(gè)Source/Oberver/Timer。
CFRun LoopModeRef
CFRun LoopModelRef代表 Run Loop 的運(yùn)行模式
-
每次Run Loop啟動(dòng)的時(shí)候倔韭,只能指定一個(gè)Mode术浪。這個(gè)Mode叫做CurrentMode。
[[NSRun Loop currentRun Loop] runMode:<(nonnull NSString *)> beforeDate:<(nonnull NSDate *)>];
如果想要切換Mode寿酌,只能退出Loop胰苏,再進(jìn)入新的Mode。這樣做的目的是分隔開不同組的Source/Oberver/Timer醇疼,讓其互不影響硕并。
-
系統(tǒng)默認(rèn)注冊的5個(gè)Mode:
- kCFRun LoopDefaultMode:App的默認(rèn)Mode法焰,通常主線程是在這個(gè)Mode下運(yùn)行。
- UITrackingRun LoopMode:界面跟蹤 Mode倔毙,用于 ScrollView 追蹤觸摸滑動(dòng)埃仪,保證界面滑動(dòng)時(shí)不受其他 Mode 影響。
- UIInitializationRun LoopMode: 在剛啟動(dòng) App 時(shí)第進(jìn)入的第一個(gè) Mode陕赃,啟動(dòng)完成后就不再使用卵蛉。
- GSEventReceiveRun LoopMode: 接受系統(tǒng)事件的內(nèi)部 Mode,通常用不到么库。
- kCFRun LoopCommonModes: 這是一個(gè)占位用的Mode傻丝,不是一種真正的Mode。
CFRun LoopTimerRef
CFRun LoopTimerRef是基于時(shí)間的觸發(fā)器
-
舉例:
//此方法是通過Run Loop實(shí)現(xiàn)的诉儒,Mode為:kCFRun LoopDefaultMode [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES]; //等價(jià)于 NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES]; [[NSRun Loop currentRun Loop] addTimer:timer forMode:NSDefaultRun LoopMode];
CFRun LoopSourceRef
- CFRun LoopSourceRef是事件源葡缰。(輸入源)
- Source的分類
-
Source0:非基于Port的。(舉例:按鈕點(diǎn)擊事件)
Source1:基于Port的允睹,通過內(nèi)核和其他線程通信运准、接收幌氮、分發(fā)系統(tǒng)事件缭受。(舉例:手指點(diǎn)擊屏幕的時(shí)候,先把事件包裝成一個(gè)Event该互,先到Source1米者,之后分發(fā)個(gè)Source0)
-
CFRun LoopObserverRef
CFRun LoopObserverRef是觀察者,可以監(jiān)聽Run Loop的狀態(tài)改變宇智。
-
能夠監(jiān)聽的時(shí)間點(diǎn):
/* Run Loop Observer Activities */ typedef CF_OPTIONS(CFOptionFlags, CFRun LoopActivity) { kCFRun LoopEntry = (1UL << 0), //即將進(jìn)入Run Loop kCFRun LoopBeforeTimers = (1UL << 1), //即將處理Timer kCFRun LoopBeforeSources = (1UL << 2), //即將處理Source kCFRun LoopBeforeWaiting = (1UL << 5), //即將進(jìn)入休眠 kCFRun LoopAfterWaiting = (1UL << 6), //剛從休眠中喚醒 kCFRun LoopExit = (1UL << 7), //即將退出Run Loop kCFRun LoopAllActivities = 0x0FFFFFFFU };
-
舉例實(shí)現(xiàn):
//沒有NS封裝過的函數(shù)蔓搞,只有這一種方式。 // 創(chuàng)建observer随橘,通過block創(chuàng)建.也可通過函數(shù)回調(diào)創(chuàng)建:FRunLoopObserverRefCFRunLoopObserverCreate(CFAllocatorRef allocator, CFOptionFlags activities, Boolean repeats, CFIndex order, CFRun LoopObserverCallBack callout, CFRun LoopObserverContext *context); CFRun LoopObserverRef observer = CFRun LoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRun LoopAllActivities, YES, 0, ^(CFRun LoopObserverRef observer, CFRun LoopActivity activity) { NSLog(@"----監(jiān)聽到Run Loop狀態(tài)發(fā)生改變---%zd", activity); }); //CFRun LoopObserverRef CFRun LoopObserverCreateWithHandler(CFAllocatorRef allocator, CFOptionFlags activities, Boolean repeats, CFIndex order, void (^block) (CFRun LoopObserverRef observer, CFRun LoopActivity activity)); //第一個(gè)參數(shù):CFAllocatorGetDefault();第二個(gè)參數(shù):能監(jiān)聽的狀態(tài);第三個(gè)參數(shù):是否重復(fù);第四個(gè)參數(shù):傳0; // 添加觀察者:監(jiān)聽Run Loop的狀態(tài) CFRun LoopAddObserver(CFRun LoopGetCurrent(), observer, kCFRun LoopDefaultMode); //void CFRun LoopAddObserver(CFRun LoopRef rl, CFRun LoopObserverRef observer, CFStringRef mode); //第一個(gè)參數(shù):需要監(jiān)聽的Run Loop;第二個(gè)參數(shù):觀察者;第三個(gè)參數(shù):Run Loop的模式; // 釋放Observer CFRelease(observer);
- 注意:Core Foundation(CF)的內(nèi)存管理喂分,凡是帶有Create、Copy机蔗、Retain等字眼的函數(shù)蒲祈,創(chuàng)建出來的對象,都需要在最后做一次release萝嘁。ARC是Foundation里的梆掸。
Run Loop處理邏輯:
- Run Loop的事件隊(duì)列:
- 每次運(yùn)行Run Loop,你線程的Run Loop對會自動(dòng)處理之前未處理的消息牙言,并通知相關(guān)的觀察者酸钦。具體的順序如下:
- 通知觀察者Run Loop已經(jīng)啟動(dòng)。
- 通知觀察者任何即將要開始的定時(shí)器咱枉。
- 通知觀察者任何即將啟動(dòng)的非基于端口的源卑硫。
- 啟動(dòng)任何準(zhǔn)備好的非基于端口的源徒恋。
- 如果基于端口的源準(zhǔn)備好并處于等待狀態(tài),立即啟動(dòng)拔恰;并進(jìn)入步驟9因谎。
- 通知觀察者線程進(jìn)入休眠。
- 將線程置于休眠直到任一下面的事件發(fā)生:
- 某一事件到達(dá)基于端口的源颜懊。
- 定時(shí)器啟動(dòng)财岔。
- Run Loop設(shè)置的時(shí)間已經(jīng)超時(shí)。
- Run Loopp被顯式喚醒河爹。
- 通知觀察者線程將被喚醒匠璧。
- 處理未處理的事件。
- 如果用戶定義的定時(shí)器啟動(dòng)咸这,處理定時(shí)器事件并重啟Run Loop夷恍。進(jìn)入步驟2。
- 如果輸入源啟動(dòng)媳维,傳遞相應(yīng)的消息酿雪。
- 如果Run Loop被顯式喚醒而且時(shí)間還沒超時(shí),重啟Run Loop侄刽。進(jìn)入步驟2指黎。
- 通知觀察者Run Loop結(jié)束。
- 每次運(yùn)行Run Loop,你線程的Run Loop對會自動(dòng)處理之前未處理的消息牙言,并通知相關(guān)的觀察者酸钦。具體的順序如下:
Run Loop應(yīng)用
-
啟動(dòng)Run Loop
[[NSRunLoop currentRunLoop] run]; //等于 [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; //等于 [[NSRunLoop currentRunLoop] runUntilDate:[NSDate distantFuture]];
-
只在NSDefaultRunLoopMode模式下顯示圖片
[self.imageView performSelector:@selector(setImage:) withObject:[UIImage imageNamed:@"placeholder"] afterDelay:3.0 inModes:@[NSDefaultRunLoopMode]];
-
常駐線程州丹,保證線程不死
[[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSDefaultRunLoopMode]; [[NSRunLoop currentRunLoop] run]; //或者(不推薦) while(flag) { [[NSRunLoop currentRunLoop] run]; }
-
子線程定時(shí)做事情(NSTimer)
NSTimer *time = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(<selector>) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] addTimer:time forMode:NSDefaultRunLoopMode]; [[NSRunLoop currentRunLoop] run]; //或者 NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(<selector>) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] run];