Runloop

RunLoop

  • 保持程序點持續(xù)運行
  • 處理App的各種事件
  • 節(jié)省CPU資源(該做事的時候做事,該休息的時候休息) 提高程序性能.實現(xiàn)省電,流暢,響應速度快,用戶體驗好。

RunLoop定義

當有持續(xù)的異步任務需求時,我們會創(chuàng)建一個獨立的生命周期可控的線程.RunLoop就是控制線程生命周期并接收事件進行處理的機制。RunLoop是iOS事件響應與任務處理最核心的機制,它貫穿了iOS整個系統(tǒng)。 運用到RunLoop的框架是 Foundation 和 CoreFoundation C語言框架

RunLoop內(nèi)部實現(xiàn)原理

  • 1.有一個判斷條件,滿足條件就無限循環(huán)(其實就是一個 do { ... } while函數(shù))
  • 2.線程得到喚醒事件被喚醒,事件處理完畢之后,回到睡眠狀態(tài),等待下次喚醒。

RunLoop特性

  • 主線程的RunLoop在應用啟動的時候就會創(chuàng)建
  • 其它線程則需要在該線程下手動啟動
  • 不能自己創(chuàng)建RunLoop對象
  • RunLoop并不是線程安全的,所以需要避免在其它線程上調(diào)用當前線程的RunLoop
  • RunLoop負責管理autorelease pools
  • RunLoop負責各類處理消息事件(例如觸摸事件、點擊事件等等

RunLoop與線程的關(guān)系

  • RunLoop是用來管理線程的,每條線程都有唯一一個與之對應的RunLoop對象
  • 當線程的RunLoop開啟后,線程就會在執(zhí)行完任務后,處于休眠狀態(tài),隨時等待接受新的任務,而不是退出。只有主線程的RunLoop是默認開啟的,所以程序在開啟后會一直運行,不會退出。其它線程的RunLoop如果需要開啟,則手動開啟。
  • 線程在執(zhí)行中的休眠和激活就是由RunLoop對象來進行管理的。

RunLoop五種模式

  • NSDefauleRunLoopMode(默認模式)
  • UITrackingRunLoopMode(只在拖拽的時候觸發(fā)的模式): 定時器會在 UITrackingRunLoopMode 模式下工作.一旦進入其他模式,定時器就不會被執(zhí)行.RunLoop只能執(zhí)行一種模式,拖拽使用時的Mode
  • NSRunLoopCommonModes(通用模式): 標記為Commen Modes的模式,UITrackingRunLoopMode NSDefaultRnuLoopMode 在這兩種模式下都可以運行
  • UIInitializationRunLoopMode(初始RunLoop):在剛啟動App時進入的第一個Mode,啟動完成后就用不到了。
  • GSEventReceiveRunLoopMode(事件接收): 接受系統(tǒng)事件的內(nèi)部Mode,通常用不到。
NSTimer *timer =  [NSTimer timerWithTimeInterval:1 target:self selector:@selector(run) userInfo:nil repeats:YES];

[[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];
// [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
// [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

RunLoop處理的模式的三大塊內(nèi)容: Source 、 Observer、Timer

  • 1.Timer:定時器

  • 2.Source:輸入源 / 事件源. 分類:

    • port-based Source,與其它線程進行交互,蘋果內(nèi)部的Source
    • Custom Input Source:自定義輸入源
    • Cocoa Perform Selector Source:處理 Perform afterDelay...事件源.
      按照函數(shù)調(diào)用棧,Source 的 分類:
    • 1.非基于Port的
    • 2.基于Port的,通過內(nèi)核和其它線程通信,接收,分發(fā)系統(tǒng)事件。
  • 3.Observer:觀察者.

     // 添加RunLoop觀察者,監(jiān)聽RunLoop狀態(tài),
     CFRunLoopAddObserver(<#CFRunLoopRef rl#>, <#CFRunLoopObserverRef observer#>, <#CFRunLoopMode mode#>)
    
    

    基本用法:

    CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopEntry, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
        NSLog(@"監(jiān)聽到RunLoop發(fā)生改變");
    });
    
    // 添加觀察者
    CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);
    
    // 釋放觀察者 凡是C語言通過retain/create/copy/創(chuàng)建出來的對象記得要釋放
    CFRelease(observer);
    
    // <#CFAllocatorRef allocator#>:默認值 CFAllocatorGetDefault()
    // <#CFOptionFlags activities#>:要監(jiān)聽哪些活動狀態(tài)
    /*
        typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
            kCFRunLoopEntry, // 1   進入RunLoop循環(huán)
            kCFRunLoopBeforeTimers, // 2 處理定時前回調(diào)
            kCFRunLoopBeforeSources, // 4 處理輸入源/事件源的事件事件
            kCFRunLoopBeforeWaiting, // 32 RunLoop睡眠前調(diào)用
            kCFRunLoopAfterWaiting, // 64 runloop喚醒后調(diào)用
            kCFRunLoopExit, // 128 退出RunLoop
            kCFRunLoopAllActivities 
        };
     */
    
    // <#Boolean repeats#>:是否重復,默認為YES
    // <#CFIndex order#>:默認為0
    

整體處理邏輯

1.通知Observer,即將進入RunLoop (Observer) --> 2.通知Observer將要處理Timer (Observer) --> 3.通知Observer,將要處理Source() (Observer) --> 4.處理Source0 --> 5.如果有Source1,跳到第九9步 --> 6.通知Observer,線程即將進入睡眠狀態(tài) --> 7.休眠,等待喚醒 --> 8.通知Observer,線程剛被喚醒 --> 9.處理喚醒時收到的消息,之后跳回2. --> 10.通知Observer,RunLoop即將退出

RunLoop應用實踐

  • 維護線程的生命周期,讓線程不會自動退出,通過變量手動設置啟動/退出
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
while (!self.isCancelled && !self.isFinished) {
    @autoreleasepool {
            [runLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:3]];
    }
}
  • 創(chuàng)建常駐線程,執(zhí)行一些會一直存在的任務。該線程的生命周期與App的主線程生命周期一樣
@autoreleasepool {
        NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
        [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
        [runLoop run];
}
  • 在一定時間內(nèi)監(jiān)聽某中事件,或者執(zhí)行某種任務的線程
// 在30分鐘內(nèi),每隔30秒執(zhí)行onTimerFired:。這種場景一般出現(xiàn)在:  我需要在App啟動之后,在一定時間內(nèi)持續(xù)更新某項數(shù)據(jù)
@autoreleasepool {
    NSRunLoop * runLoop = [NSRunLoop currentRunLoop];
    NSTimer * udpateTimer = [NSTimer timerWithTimeInterval:30
                                                    target:self
                                                  selector:@selector(onTimerFired:)
                                                  userInfo:nil
                                                   repeats:YES];
    [runLoop addTimer:udpateTimer forMode:NSRunLoopCommonModes];
    [runLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:60*30]];
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

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

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