亚洲欧美日韩熟女|做爱高潮视频网址|国产一区二区三级片|国产Av中文字幕www.性色av|亚洲婷婷永久免费|国产高清中文字幕|欧美变态网站久re视频精品|人妻AV鲁丝第一页|天堂AV一区二区在线观看|综合 91在线精品

RunLoop 原理及核心機(jī)制

2023-05-27



RunLoop 原理及核心機(jī)制







從iOS開始就沒有對RunLoop進(jìn)行過深入的研究,非常慚愧。碰巧前陣子負(fù)責(zé)性能優(yōu)化項(xiàng)目,需要利用RunLoop進(jìn)行性能優(yōu)化和性能測試,借此機(jī)會對RunLoop的原理和特點(diǎn)進(jìn)行了深入的研究。


定義RunLoop

如果需要持續(xù)的異步任務(wù),我們將創(chuàng)造一個獨(dú)立的生命周期可控的過程。RunLoop是一種控制線程生命周期并接受事件處理的機(jī)制。


RunLoop是iOS事件響應(yīng)和任務(wù)處理的核心機(jī)制,它貫穿整個iOS系統(tǒng)。


Foundation: NSRunLoop
Core Foundation: CFRunLoop 核心部分,代碼開源,C 語言寫作,跨平臺


目的

通過RunLoop機(jī)制實(shí)現(xiàn)節(jié)能、平穩(wěn)、快速響應(yīng)、良好的客戶體驗(yàn)。


理解

過程是一家工廠,過程是一條流水線,Run 在流水線上,Loop就是主管;當(dāng)工廠收到商家的訂單分配給這條流水線時,Run Loop開始了這條流水線,讓流水線移動,進(jìn)行生產(chǎn);當(dāng)產(chǎn)品完成后,Run Loop將暫時停止流水線,節(jié)約能源。
RunLoop管理流水線,流水線不會因?yàn)闊o所事事而被工廠銷毀;而且不需要流水線的時候,RunLoop這個主管就會被解雇,也就是退出流程,釋放全部資源。


RunLoop并不是iOS平臺的專屬概念,在任何平臺的多線程編程中,Android的Looper都需要類似RunLoop的循環(huán)機(jī)制來實(shí)現(xiàn),以控制線程的生命周期。


特點(diǎn)

  • 當(dāng)使用啟動時,主線程的RunLoop將自動建立
  • 另外一個過程需要在這個過程下自行啟動。
  • 無法建立自己的RunLoop
  • RunLoop不是線程安全的,所以需要避免將RunLoop調(diào)用到其他過程中。
  • 負(fù)責(zé)管理autoreleaseasease的RunLoop pools
  • RunLoop負(fù)責(zé)處理消息事件,即輸入源事件和記時器事件

RunLoop機(jī)制

主線程 (有 RunLoop 的進(jìn)程) 幾乎所有函數(shù)都是從以下六個函數(shù)中調(diào)整起來的:


  • CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION
    CFRunloop is calling out to an abserver callback function
    用來向外界報告 RunLoop 當(dāng)前狀態(tài)的變化,框架中的許多機(jī)制都是由 RunLoopObserver 觸發(fā),如 CAAnimation
  • CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK
    CFRunloop is calling out to a block
    消息通知,perform,非延遲、調(diào)用dispatch,回調(diào)block,KVO
  • CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE
    CFRunloop is servicing the main desipatch queue
  • CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION
    CFRunloop is calling out to a timer callback function
    perform延遲, 延遲dispatch調(diào)用
  • CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0__PERFORM_FUNCTION
    CFRunloop is calling out to a source 0 perform function
    處理App內(nèi)部事件,App本身負(fù)責(zé)管理(觸發(fā)),例如UIEvent。、CFSocket。通用函數(shù)調(diào)用,系統(tǒng)調(diào)用
  • CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION
    CFRunloop is calling out to a source 1 perform function
    由RunLoop和核心管理,Mach CFMachPort驅(qū)動程序、CFMessagePort
  • RunLoop 架構(gòu)

??


  • RunLoop 運(yùn)行時



以下六種狀態(tài)主要有:


  • kCFRunLoopEntry -- 進(jìn)入runloop循環(huán)循環(huán)循環(huán)
  • kCFRunLoopBeforeTimers -- 定期調(diào)用前回調(diào)處理
  • kCFRunLoopBeforeSources -- 處理input sources事件
  • kCFRunLoopBeforeWaiting -- 睡前調(diào)用runloop
  • kCFRunLoopAfterWaiting -- 喚起后調(diào)用runloop
  • kCFRunLoopExit -- 退出runloop

RunLoop 運(yùn)轉(zhuǎn)時調(diào)用棧

  • 運(yùn)行主線程App時



  • ObserverRunLoopAutorelease Pool的關(guān)系



UIKit 通過 RunLoopObserver 在 RunLoop 兩次 Sleep 間對 Autorelease Pool 進(jìn)行 Pop 和 Push 將這次 Loop 中產(chǎn)生的 Autorelease 目標(biāo)釋放。


  • 掛起和喚起RunLoop



mach端口_port
調(diào)用mach_msg監(jiān)控喚起端口,喚起前系統(tǒng)內(nèi)核將此線程掛起,停留在mach_msg_trap狀態(tài)。
這個端口的msg由另一個過程發(fā)送到核心后,trap狀態(tài)被喚起,RunLoop繼續(xù)工作。



消息事件支持RunLoop(Events)

  • RunLoop



  • 支持輸入源的接收處理(Input Source)包括:

Mach系統(tǒng) Port事件,是一種通信事件
定制輸入事件



  • 對處理定時源的支持(Timer)事件
  • 啟動RunLoop前,必須添加監(jiān)控輸入源事件或定時源事件,否則調(diào)用。[runloop run]將直接返回,而不進(jìn)入循環(huán)使進(jìn)程長駐。

如果沒有添加任何輸入源事件或Timer事件,過程將繼續(xù)循環(huán)和空轉(zhuǎn),CPU時間片將永遠(yuǎn)占用,資源的合理分配將無法實(shí)現(xiàn)。
沒有while循環(huán),也沒有添加任何輸入源或Timer的過程,過程將直接完成,并被系統(tǒng)回收。



//錯誤的做法 
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
while (!self.isCancelled && !self.isFinished) {
    [runLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:3]];
};

//正確的做法
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
while (!self.isCancelled && !self.isCancelled && !self.isFinished) {
    @autoreleasepool {
        [runLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:3]];
    }
}

Run Loop Modes

  • 理解
    Run Loop Mode是流水線上支持生產(chǎn)的產(chǎn)品類型。流水線只能在一定時間內(nèi)以一種模式運(yùn)行,生產(chǎn)某種類型的產(chǎn)品。新聞事件是訂單。
  • Cocoa定義了四中Mode

Default:NSDefaultRunLoopMode,Run是默認(rèn)的 當(dāng)Loop沒有指定Mode時,默認(rèn)情況下,它會在Default上運(yùn)行。 Mode下
Connection:NSConnectionReplyMode,對NSConnection事件進(jìn)行監(jiān)控處理。
Modal:NSModalPanelRunLoopMode,OS Modal面板事件X
Event tracking:UITrackingRunLoopMode,拖動事件
Common mode:NSRunLoopCommonModes,這是一種集合方式。當(dāng)一個事件來源被綁定到這個模式集合時,它相當(dāng)于綁定到集合中的每一種方式。



  • RunLoop可以通過[acceptInputForMode:beforeDate:]和[runMode:beforeDate:]指定一段時間內(nèi)的運(yùn)行模式。如果沒有指定,RunLoop默認(rèn)會在Default下運(yùn)行(runModede反復(fù)調(diào)用):NSDefaultRunLoopMode beforDate:)
  • 啟動主線程中的記時器Timer,然后拖動UITableView或UIScrollView,記時器不會執(zhí)行。因?yàn)?,為了更好的客戶體驗(yàn),Event在主線程中。 優(yōu)先考慮tracking模式??蛻敉蟿涌丶r,主線程的Run 在Event中運(yùn)行Loop tracking 在Mode下,建立的Timer默認(rèn)與Defaultt相關(guān)聯(lián)。 Mode,所以系統(tǒng)不會立即執(zhí)行Default 接受Mode下的事件。解決方法:
NSTimer * timer = [NSTimer scheduledTimerWithTimeInterval:1.0
                                                   target:self
                                                 selector:@selector(timerFireMethod:)
                                                 userInfo:nil
                                                  repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]; 
//或 
[[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];

[timer fire];

Run Loop應(yīng)用實(shí)踐

Run Loop主要有以下三個應(yīng)用領(lǐng)域:


  • 維持過程的生命周期,使過程不會自動退出,isFinished在Yes時退出。
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
while (!self.isCancelled && !self.isFinished) {
    @autoreleasepool {
            [runLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:3]];
    }
}
  • 建立一個長期的停留過程,執(zhí)行一些將永遠(yuǎn)存在的任務(wù)。這個過程的生命周期和應(yīng)用程序一樣。
@autoreleasepool {
        NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
        [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
        [runLoop run];
}
  • 監(jiān)控某一事件,或者在一定時間內(nèi)執(zhí)行某一任務(wù)的過程。
    下面的代碼,在30分鐘內(nèi),每30秒執(zhí)行onTimerFired。:。這樣的情況一般都會出現(xiàn),比如我需要在使用之后,在一定的時間內(nèi)不斷更新某些數(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]];
}
  • RunLoop在AFNetworking中的建立
  (void)networkRequestThreadEntryPoint:(id)__unused object {
    @autoreleasepool {
        [[NSThread currentThread] setName:@"AFNetworking"];

        NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
         // 這兒主要是監(jiān)控一個 port,目的就是讓這個 Thread 不會回收
        [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode]; 
        [runLoop run];
    }
}

  (NSThread *)networkRequestThread {
    static NSThread *_networkRequestThread = nil;
    static dispatch_once_t oncePredicate;
    dispatch_once(&oncePredicate, ^{
        _networkRequestThread =
        [[NSThread alloc] initWithTarget:self
                                selector:@selector(networkRequestThreadEntryPoint:)
                                  object:nil];
        [_networkRequestThread start];
    });
    return _networkRequestThread;
}




本文僅代表作者觀點(diǎn),版權(quán)歸原創(chuàng)者所有,如需轉(zhuǎn)載請在文中注明來源及作者名字。

免責(zé)聲明:本文系轉(zhuǎn)載編輯文章,僅作分享之用。如分享內(nèi)容、圖片侵犯到您的版權(quán)或非授權(quán)發(fā)布,請及時與我們聯(lián)系進(jìn)行審核處理或刪除,您可以發(fā)送材料至郵箱:service@tojoy.com