91无码视频一区|蜜臀福利在线观看|日韩一极黄色视频|色欲人妻少妇Av一区二区|婷婷香蕉视频欧美三级片黄色|一级A片刺激高潮|国产精品污污久久|日韩黄色精品日韩久久综合网|中国一级片电影在线|超碰乱码久久久免费

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

2023-05-27



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







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


定義RunLoop

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


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


Foundation: NSRunLoop
Core Foundation: CFRunLoop 核心部分,代碼開源,C 語(yǔ)言寫作,跨平臺(tái)


目的

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


理解

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


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


特點(diǎn)

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

RunLoop機(jī)制

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


  • CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION
    CFRunloop is calling out to an abserver callback function
    用來(lái)向外界報(bào)告 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ū)動(dòng)程序、CFMessagePort
  • RunLoop 架構(gòu)

??


  • RunLoop 運(yùn)行時(shí)



以下六種狀態(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)時(shí)調(diào)用棧

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



  • ObserverRunLoopAutorelease Pool的關(guān)系



UIKit 通過(guò) RunLoopObserver 在 RunLoop 兩次 Sleep 間對(duì) 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)。
這個(gè)端口的msg由另一個(gè)過(guò)程發(fā)送到核心后,trap狀態(tài)被喚起,RunLoop繼續(xù)工作。



消息事件支持RunLoop(Events)

  • RunLoop



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

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



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

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



//錯(cuò)誤的做法 
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)品類型。流水線只能在一定時(shí)間內(nèi)以一種模式運(yùn)行,生產(chǎn)某種類型的產(chǎn)品。新聞事件是訂單。
  • Cocoa定義了四中Mode

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



  • RunLoop可以通過(guò)[acceptInputForMode:beforeDate:]和[runMode:beforeDate:]指定一段時(shí)間內(nèi)的運(yùn)行模式。如果沒(méi)有指定,RunLoop默認(rèn)會(huì)在Default下運(yùn)行(runModede反復(fù)調(diào)用):NSDefaultRunLoopMode beforDate:)
  • 啟動(dòng)主線程中的記時(shí)器Timer,然后拖動(dòng)UITableView或UIScrollView,記時(shí)器不會(huì)執(zhí)行。因?yàn)?,為了更好的客戶體驗(yàn),Event在主線程中。 優(yōu)先考慮tracking模式??蛻敉蟿?dòng)控件時(shí),主線程的Run 在Event中運(yùn)行Loop tracking 在Mode下,建立的Timer默認(rèn)與Defaultt相關(guān)聯(lián)。 Mode,所以系統(tǒng)不會(huì)立即執(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主要有以下三個(gè)應(yīng)用領(lǐng)域:


  • 維持過(guò)程的生命周期,使過(guò)程不會(huì)自動(dòng)退出,isFinished在Yes時(shí)退出。
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
while (!self.isCancelled && !self.isFinished) {
    @autoreleasepool {
            [runLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:3]];
    }
}
  • 建立一個(gè)長(zhǎng)期的停留過(guò)程,執(zhí)行一些將永遠(yuǎn)存在的任務(wù)。這個(gè)過(guò)程的生命周期和應(yīng)用程序一樣。
@autoreleasepool {
        NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
        [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
        [runLoop run];
}
  • 監(jiān)控某一事件,或者在一定時(shí)間內(nèi)執(zhí)行某一任務(wù)的過(guò)程。
    下面的代碼,在30分鐘內(nèi),每30秒執(zhí)行onTimerFired。:。這樣的情況一般都會(huì)出現(xiàn),比如我需要在使用之后,在一定的時(shí)間內(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)控一個(gè) port,目的就是讓這個(gè) Thread 不會(huì)回收
        [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)載請(qǐng)?jiān)谖闹凶⒚鱽?lái)源及作者名字。

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