iOS進(jìn)階01:Runloop

一、Runloop的定義

Runloop就是運(yùn)行時(shí)循環(huán),保證程序一直運(yùn)行下去

  • Runloop實(shí)際上是一個(gè)對(duì)象律姨,這個(gè)對(duì)象用于處理程序運(yùn)行過(guò)程中遇到的各種事件(觸摸,UI刷新臼疫,定時(shí)器择份,performSelector等等),保證程序的持續(xù)運(yùn)行
  • Runloop在沒(méi)有事件需要處理的時(shí)候烫堤,會(huì)使線程進(jìn)入休眠狀態(tài)荣赶,從而減少CPU的消耗,提高程序性能鸽斟。
  • Runloop是一種消息機(jī)制的處理模式

二拔创、 Runloop的作用

  • 保證程序持續(xù)運(yùn)行
  • 喚醒線程,響應(yīng)程序的使用
  • 在沒(méi)有事件需要處理的時(shí)候富蓄,使線程進(jìn)入休眠狀態(tài)剩燥,減少CPU的消耗。

三立倍、Runloop與線程的關(guān)系

  • 線程與Runloop是一一對(duì)應(yīng)的關(guān)系

從代碼doit = CFEqual(curr->_mode, curMode) || (CFEqual(curr->_mode, kCFRunLoopCommonModes) && CFSetContainsValue(commonModes, curMode))看出:
當(dāng)前runloop模式等于傳入的model灭红,或者是runloop模式是組合模式kCFRunLoopCommonModes,doit=YES口注,就會(huì)執(zhí)行变擒。
這也是為什么NSTimer加入到kCFRunLoopCommonModes模式下的runloop時(shí),不會(huì)因?yàn)轫?yè)面滑動(dòng)造成定時(shí)器延遲的原因了寝志。

static Boolean __CFRunLoopDoBlocks(CFRunLoopRef rl, CFRunLoopModeRef rlm) { // Call with rl and rlm locked
    // ...
    if (CFStringGetTypeID() == CFGetTypeID(curr->_mode)) {
        doit = CFEqual(curr->_mode, curMode) || (CFEqual(curr->_mode, kCFRunLoopCommonModes) && CFSetContainsValue(commonModes, curMode));
        } else {
        doit = CFSetContainsValue((CFSetRef)curr->_mode, curMode) || (CFSetContainsValue((CFSetRef)curr->_mode, kCFRunLoopCommonModes) && CFSetContainsValue(commonModes, curMode));
    }
    if (!doit) prev = curr;
    if (doit) {
        if (prev) prev->_next = item;
        if (curr == head) head = item;
        if (curr == tail) tail = prev;
        void (^block)(void) = curr->_block;
            CFRelease(curr->_mode);
            free(curr);
        if (doit) {
                __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__(block);
            did = true;
        }
            Block_release(block); // do this before relocking to prevent deadlocks where some yahoo wants to run the run loop reentrantly from their dealloc
    }
    }
    __CFRunLoopLock(rl);
    __CFRunLoopModeLock(rlm);
    if (head) {
    tail->_next = rl->_blocks_head;
    rl->_blocks_head = head;
        if (!rl->_blocks_tail) rl->_blocks_tail = tail;
    }
    return did;
}

四娇斑、Runloop應(yīng)用

1. 使用Runloop來(lái)監(jiān)控程序的卡頓

參考文章:
深入理解RunLoop
iOS監(jiān)控卡頓

原理:
1.需要?jiǎng)?chuàng)建一個(gè)CFRunLoopObserverContext觀察者,然后將觀察者runLoopObserver添加到主線程 RunLoop的common模式下觀察
2.創(chuàng)建一個(gè)持續(xù)的子線程專門用來(lái)監(jiān)控主線程的RunLoop狀態(tài)
3.重點(diǎn)關(guān)注RunLoop 在進(jìn)入睡眠之前和喚醒后的兩個(gè) loop狀態(tài)定義的值分別是 kCFRunLoopBeforeSources 和 kCFRunLoopAfterWaiting材部,如果停留在這兩個(gè)狀態(tài)的連續(xù)超時(shí)50ms悠菜,則認(rèn)為是卡頓。

static void runLoopObserverCallBack(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info){
    SeMonitorController *instrance = [SeMonitorController sharedInstance];
    instrance->_activity = activity;
    // 發(fā)送信號(hào)
    dispatch_semaphore_t semaphore = instrance->_semaphore;
    dispatch_semaphore_signal(semaphore);
}

- (void)registerObserver
{
    CFRunLoopObserverContext context = {0,(__bridge void*)self,NULL,NULL};
    _observer = CFRunLoopObserverCreate(kCFAllocatorDefault,
                                                            kCFRunLoopAllActivities,
                                                            YES,
                                                            0,
                                                            &runLoopObserverCallBack,
                                                            &context);
    CFRunLoopAddObserver(CFRunLoopGetMain(), _observer, kCFRunLoopCommonModes);
   // 創(chuàng)建信號(hào)

    _semaphore = dispatch_semaphore_create(0);
    // 在子線程監(jiān)控時(shí)長(zhǎng)
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        while (YES) {
            // 假定連續(xù)5次超時(shí)50ms認(rèn)為卡頓(當(dāng)然也包含了單次超時(shí)250ms)
            long st = dispatch_semaphore_wait(_semaphore, dispatch_time(DISPATCH_TIME_NOW, 0.05f*NSEC_PER_MSEC));
            if (st != 0){
                if (_activity==kCFRunLoopBeforeSources || _activity==kCFRunLoopAfterWaiting)
                {
                    if (++_countTime < 5)   continue;
                     
                    NSLog(@"something lag");
                }
            }
            _countTime = 0;
        }
    });
}
2. 使用CADisplayLink來(lái)監(jiān)控FPS

// 屏幕刷新頻率
// 將CADisplayLink添加到主Runloop中败富,來(lái)監(jiān)控主線的屏幕刷新頻率

_link = [CADisplayLink displayLinkWithTarget:weakself selector:@selector(tick:)];
[_link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市摩窃,隨后出現(xiàn)的幾起案子兽叮,更是在濱河造成了極大的恐慌芬骄,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鹦聪,死亡現(xiàn)場(chǎng)離奇詭異账阻,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)泽本,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門淘太,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人规丽,你說(shuō)我怎么就攤上這事蒲牧。” “怎么了赌莺?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵冰抢,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我艘狭,道長(zhǎng)挎扰,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任巢音,我火速辦了婚禮遵倦,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘官撼。我一直安慰自己梧躺,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布歧寺。 她就那樣靜靜地躺著燥狰,像睡著了一般。 火紅的嫁衣襯著肌膚如雪斜筐。 梳的紋絲不亂的頭發(fā)上龙致,一...
    開(kāi)封第一講書(shū)人閱讀 51,292評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音顷链,去河邊找鬼目代。 笑死,一個(gè)胖子當(dāng)著我的面吹牛嗤练,可吹牛的內(nèi)容都是我干的榛了。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼煞抬,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼霜大!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起革答,我...
    開(kāi)封第一講書(shū)人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤战坤,失蹤者是張志新(化名)和其女友劉穎曙强,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體途茫,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡碟嘴,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了囊卜。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片娜扇。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖栅组,靈堂內(nèi)的尸體忽然破棺而出雀瓢,到底是詐尸還是另有隱情,我是刑警寧澤笑窜,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布致燥,位于F島的核電站,受9級(jí)特大地震影響排截,放射性物質(zhì)發(fā)生泄漏嫌蚤。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一断傲、第九天 我趴在偏房一處隱蔽的房頂上張望脱吱。 院中可真熱鬧,春花似錦认罩、人聲如沸箱蝠。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)宦搬。三九已至,卻和暖如春劫拗,著一層夾襖步出監(jiān)牢的瞬間间校,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工页慷, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留憔足,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓酒繁,卻偏偏與公主長(zhǎng)得像滓彰,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子州袒,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354