Runloop 簡(jiǎn)介

Runloop 是 iOS 和 OSX 中和線程相關(guān)的基礎(chǔ)概念。提供了線程循環(huán)處理事件的能力,當(dāng)有事件處理時(shí)喚醒線程工作,空閑時(shí)使線程進(jìn)入休眠,以合理的利用系統(tǒng)資源。

Runloop 是線程相關(guān)的概念,和線程是一一對(duì)應(yīng)的。一個(gè)線程對(duì)應(yīng)一個(gè)runloop,默認(rèn)情況下,主線程的 runloop 是啟動(dòng)的,后臺(tái)線程的 runloop 需要自己?jiǎn)?dòng)。

Runloop 的工作模型類似 windows 中的消息機(jī)制(Event loop),接受事件(消息)->處理->等待新事件(消息),偽代碼如下:

loop()
{
    init();
    while(get_message(&msg) != quit){
        handle_message(msg);
    }
}

Runloop 中需要處理的事件分2類:

  1. 輸入源(input source):分發(fā)異步事件,通常都是來(lái)自其他線程或者Application。
  • performSelector源
  • 基于端口的源(mach port)
  • 自定義輸入源
  1. 計(jì)時(shí)器:定時(shí)的或者一定間隔的觸發(fā)同步事件。

Runloop 的運(yùn)行結(jié)構(gòu)圖如下圖:


2015-08-23-ios-runloop.jpg

Runloop 其實(shí)是一個(gè)對(duì)象,提供了一個(gè)入口函數(shù)來(lái)執(zhí)行上面的事件循環(huán),在函數(shù)內(nèi)部實(shí)現(xiàn)了接受消息->處理->等待新消息這樣的一個(gè)循環(huán)流程,直到循環(huán)結(jié)束。

Runloop 運(yùn)行中會(huì)發(fā)出許多通知,比如狀態(tài)的改變,可以監(jiān)聽(tīng)這些通知作對(duì)應(yīng)的處理。
iOS 和 OSX 中提供了2個(gè)這樣的對(duì)象:NSRunloop和CFRunLoopRef。

內(nèi)部邏輯大致如下圖:


2015-08-23-ios-runloop_1.png

運(yùn)行模式

運(yùn)行模式定義了一個(gè)集合,當(dāng) Runloop 運(yùn)行在某個(gè)模式下時(shí),只會(huì)監(jiān)聽(tīng)某些類型的輸入源事件和計(jì)時(shí)器事件,以及分發(fā)某些特定種類的通知,啟動(dòng) Runloop 時(shí)會(huì)指定一種模式。

常見(jiàn)的一些運(yùn)行模式:

  • NSDefaultRunLoopMode:默認(rèn)模式,包括了大部分的操作事件,絕大部份情況下都應(yīng)該使用這個(gè)模式配置自己的 runloop
  • NSEventTrackingRunLoopMode:典型的當(dāng) scrollView 滾動(dòng)的時(shí)候是運(yùn)行在該模式下,此時(shí)的不接受Timer事件,所以Timer會(huì)失效
  • NSRunLoopCommonModes:模式組,一個(gè)模式將自己標(biāo)記為“common”屬性后就會(huì)在該組中,運(yùn)行在該模式下,能處理的事件就是組中各個(gè)模式能處理事件的合集,在默認(rèn)情況下,NSDefaultRunLoopMode 和NSEventTrackingRunLoopMode 被標(biāo)記為 “common” 屬性

輸入源

  • 基于端口的源:監(jiān)聽(tīng)Mach port,cocoa 提供了內(nèi)置的類來(lái)實(shí)現(xiàn)這類輸入源 NSPort (IPC相關(guān))
  • 自定義輸入源:
  • PerformSelector源:主要是那些和時(shí)間能扯上關(guān)系的API,比如:(其實(shí)是通過(guò)timer實(shí)現(xiàn)的)
    • performSelectorOnMainThread:withObject:waitUntilDone:
    • performSelector:withObject:afterDelay:
    • performSelector:onThread:withObject:waitUntilDone:

Runloop 的使用

  • 使用端口或者自定義輸入源來(lái)實(shí)現(xiàn)線程間的通信
  • 在線程中使用計(jì)時(shí)器
  • 使用performSelector方法
  • 保持線程執(zhí)行周期性的任務(wù)

Runloop 的應(yīng)用

  • Autorelease pool:runloop 會(huì)自動(dòng)維護(hù)autorelease pool的創(chuàng)建和釋放,autorelease pool 會(huì)在下一次runloop循環(huán)之前釋放 pool 中的對(duì)象,所以在像for,while這樣的循環(huán)中,如果需要大量創(chuàng)建臨時(shí)對(duì)象時(shí)需要自己創(chuàng)建autorelease pool,避免臨時(shí)內(nèi)存峰值過(guò)高,比如圖片相關(guān)的操作
  • 事件響應(yīng)(觸摸/鎖屏/搖晃等):source1 事件
  • 手勢(shì)識(shí)別:監(jiān)聽(tīng)特定的通知,處理手勢(shì)的回調(diào)
  • 界面更新:監(jiān)聽(tīng)特定的通知,處理界面的刷新操作
  • 定時(shí)器:NSTimer 和 CADisplayLink
  • PerformSelector:AfterDelay:
  • GCD:dispatch_async(dispatch_get_main_queue(), block)

附 Runloop 的部分源碼圖:


屏幕快照 2016-01-28 上午10.33.57.png

一個(gè)使用 Runloop 的簡(jiǎn)單例子

- (void)threadMain 
{ 
    // The application uses garbage collection, so no autorelease pool is needed. 
    NSRunLoop* myRunLoop = [NSRunLoop currentRunLoop]; 
 
    // Create a run loop observer and attach it to the run loop. 
    CFRunLoopObserverContext  context = {0, self, NULL, NULL, NULL}; 
    CFRunLoopObserverRef    observer = CFRunLoopObserverCreate(kCFAllocatorDefault, 
            kCFRunLoopAllActivities, YES, 0, &myRunLoopObserver, &context); 
 
    if (observer) 
    { 
        CFRunLoopRef    cfLoop = [myRunLoop getCFRunLoop]; 
        CFRunLoopAddObserver(cfLoop, observer, kCFRunLoopDefaultMode); 
    } 
 
    // Create and schedule the timer. 
    [NSTimer scheduledTimerWithTimeInterval:0.1 target:self 
                selector:@selector(doFireTimer:) userInfo:nil repeats:YES]; 
 
    NSInteger    loopCount = 10; 
    do 
    { 
        // Run the run loop 10 times to let the timer fire. 
        [myRunLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]]; 
        loopCount--; 
    } 
    while (loopCount); 
}

案例

AFNetworking

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Run loop 剖析:Runloop 接收的輸入事件來(lái)自兩種不同的源:輸入源(intput source)和定時(shí)...
    Mitchell閱讀 12,653評(píng)論 17 111
  • 目錄1. RunLoop簡(jiǎn)介2. RunLoop的相關(guān)類3. RunLoop的應(yīng)用 1. 什么是RunLoop *...
    云中追月閱讀 639評(píng)論 0 0
  • 一、什么是runloop 字面意思是“消息循環(huán)、運(yùn)行循環(huán)”。它不是線程,但它和線程息息相關(guān)。一般來(lái)講,一個(gè)線程一次...
    WeiHing閱讀 8,324評(píng)論 11 111
  • 什么是RunLoop?從字面上來(lái)看是運(yùn)行循環(huán)的意思.內(nèi)部就是一個(gè)do{}while循環(huán),在這個(gè)循環(huán)里內(nèi)部不斷的處理...
    deve_雨軒閱讀 29,603評(píng)論 1 32
  • 看完三頁(yè) 答應(yīng)你的 乖乖關(guān)燈睡覺(jué) 好了不鬧 不能擁抱 我也乖乖睡覺(jué) 抑制不住躁動(dòng)的心 想沖上去撲倒你 還是乖乖睡覺(jué)...
    取名字啥的真的好煩閱讀 236評(píng)論 0 0

友情鏈接更多精彩內(nèi)容