runloop

NSRunLoop:
OSX/iOS 系統(tǒng)中,提供了兩個(gè)這樣的對(duì)象:NSRunLoop 和 CFRunLoopRef闰歪。
CFRunLoopRef 是在 CoreFoundation 框架內(nèi)的辅斟,它提供了純 C 函數(shù)的 API一忱,所有這些 API 都是線程安全的听皿。
NSRunLoop 是基于 CFRunLoopRef 的封裝徐紧,提供了面向?qū)ο蟮?API静檬,但是這些 API 不是線程安全的炭懊。
NSRunLoop 與線程的關(guān)系:
其實(shí)runLoop就是一個(gè)do … while()函數(shù),每個(gè)runLoop對(duì)應(yīng)一個(gè)線程他們是一一對(duì)應(yīng)的關(guān)系拂檩,關(guān)系保存在一個(gè)全局的Dictionary里邊侮腹,線程剛創(chuàng)建時(shí)沒有RunLoop,如果不主動(dòng)獲取,是不會(huì)有的稻励,RunLoop的創(chuàng)建發(fā)生在第一次獲取時(shí)父阻,RunLoop的銷毀發(fā)生在線程結(jié)束,只能在一個(gè)線程的內(nèi)部獲取它的RunLoop(主線程除外)主線程默認(rèn)有個(gè)RunLoop.
Thread包含一個(gè)CFRunLoop望抽,一個(gè)CFRunLoop包含一種CFRunLoopMode加矛,mode包含CFRunLoopSource,CFRunLoopTimer和CFRunLoopObserver煤篙。
Runloop的寄生于線程:一個(gè)線程只能有唯一對(duì)應(yīng)的runloop斟览;但這個(gè)根runloop里可以嵌套子runloops;
自動(dòng)釋放池寄生于Runloop:程序啟動(dòng)后辑奈,主線程注冊(cè)了兩個(gè)Observer監(jiān)聽runloop的進(jìn)出與睡覺苛茂。一個(gè)最高優(yōu)先級(jí)OB監(jiān)測(cè)Entry狀態(tài);一個(gè)最低優(yōu)先級(jí)OB監(jiān)聽BeforeWaiting狀態(tài)和Exit狀態(tài)鸠窗。
線程(創(chuàng)建)-->runloop將進(jìn)入-->最高優(yōu)先級(jí)OB創(chuàng)建釋放池-->runloop將睡-->最低優(yōu)先級(jí)OB銷毀舊池創(chuàng)建新池-->runloop將退出-->最低優(yōu)先級(jí)OB銷毀新池-->線程(銷毀)
RunLoop只能運(yùn)行在一種mode下妓羊,如果要換mode當(dāng)前的loop也需要停下重啟成新的。利用這個(gè)機(jī)制塌鸯,ScrollView過程中NSDefaultRunLoopMode的mode會(huì)切換UITrackingRunLoopMode來保證ScrollView的流暢滑動(dòng)不受只能在NSDefaultRunLoopMode時(shí)處理的事件影響滑動(dòng)侍瑟。同時(shí)mode還是可定制的。
NSDefaultRunLoopMode:默認(rèn)丙猬,空閑狀態(tài)
UITrackingRunLoopMode:ScrollView滑動(dòng)時(shí)
UIInitializationRunLoopMode:?jiǎn)?dòng)時(shí)
NSRunLoopCommonModes:Mode集合 Timer計(jì)時(shí)會(huì)被scrollView的滑動(dòng)影響的問題可以通過將timer添加到NSRunLoopCommonModes來解決

//然后再添加到NSRunLoopCommonModes里  
NSTimer *timer = [NSTimer timerWithTimeInterval:1.0  
    target:self  
    selector:@selector(timerTick:)  
    userInfo:nil  
    repeats:YES];  
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
/// 全局的Dictionary涨颜,key 是 pthread_t, value 是 CFRunLoopRef  
static CFMutableDictionaryRef loopsDic;  
/// 訪問 loopsDic 時(shí)的鎖  
static CFSpinLock_t loopsLock;  
  
/// 獲取一個(gè) pthread 對(duì)應(yīng)的 RunLoop茧球。  
CFRunLoopRef _CFRunLoopGet(pthread_t thread) {  
    OSSpinLockLock(&loopsLock);  
  
    if (!loopsDic) {  
        // 第一次進(jìn)入時(shí)庭瑰,初始化全局Dic,并先為主線程創(chuàng)建一個(gè) RunLoop抢埋。  
        loopsDic = CFDictionaryCreateMutable();  
        CFRunLoopRef mainLoop = _CFRunLoopCreate();  
        CFDictionarySetValue(loopsDic, pthread_main_thread_np(), mainLoop);  
    }  
  
    /// 直接從 Dictionary 里獲取弹灭。  
    CFRunLoopRef loop = CFDictionaryGetValue(loopsDic, thread));  
  
    if (!loop) {  
        /// 取不到時(shí),創(chuàng)建一個(gè)  
        loop = _CFRunLoopCreate();  
        CFDictionarySetValue(loopsDic, thread, loop);  
        /// 注冊(cè)一個(gè)回調(diào)揪垄,當(dāng)線程銷毀時(shí)穷吮,順便也銷毀其對(duì)應(yīng)的 RunLoop。  
        _CFSetTSD(..., thread, loop, __CFFinalizeRunLoop);  
    }  
  
    OSSpinLockUnLock(&loopsLock);  
    return loop;  
}  
  
CFRunLoopRef CFRunLoopGetMain() {  
    return _CFRunLoopGet(pthread_main_thread_np());  
}  
  
CFRunLoopRef CFRunLoopGetCurrent() {  
    return _CFRunLoopGet(pthread_self());  
}  

NSTimer和performSEL方法實(shí)際上是對(duì)CFRunloopTimerRef的封裝饥努;runloop啟動(dòng)時(shí)設(shè)置的最大超時(shí)時(shí)間實(shí)際上是GCD的dispatch_source_t類型捡鱼。
數(shù)據(jù)結(jié)構(gòu):

// Timer:interval:(鬧鐘間隔), tolerance:(延期時(shí)間容忍度),callout(回調(diào)函數(shù))CFRunLoopTimer {firing =..., interval = ...,tolerance = ...,next fire date = ...,callout = ...}

創(chuàng)建與生效酷愧;
//NSTimer: // 創(chuàng)建一個(gè)定時(shí)器(需要手動(dòng)加到runloop的mode中) + (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo; // 默認(rèn)已經(jīng)添加到主線程的runLoop的DefaultMode中  + (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;// performSEL方法// 內(nèi)部會(huì)創(chuàng)建一個(gè)Timer到當(dāng)前線程的runloop中(如果當(dāng)前線程沒runloop則方法無效驾诈;performSelector:onThread: 方法放到指定線程runloop中)- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay

相關(guān)類型(GCD的timer與CADisplayLink)
GCD的timer:dispatch_source_t 類型缠诅,可以精確的參數(shù),不用以來runloop和mode乍迄,性能消耗更小管引。

dispatch_source_set_timer(dispatch_source_t source, // 定時(shí)器對(duì)象 dispatch_time_t start, // 定時(shí)器開始執(zhí)行的時(shí)間 uint64_t interval, // 定時(shí)器的間隔時(shí)間 uint64_t leeway // 定時(shí)器的精度 );
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市闯两,隨后出現(xiàn)的幾起案子褥伴,更是在濱河造成了極大的恐慌,老刑警劉巖生蚁,帶你破解...
    沈念sama閱讀 221,576評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件噩翠,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡邦投,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門擅笔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來志衣,“玉大人,你說我怎么就攤上這事猛们∧罡” “怎么了?”我有些...
    開封第一講書人閱讀 168,017評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵弯淘,是天一觀的道長(zhǎng)绿店。 經(jīng)常有香客問我,道長(zhǎng)庐橙,這世上最難降的妖魔是什么假勿? 我笑而不...
    開封第一講書人閱讀 59,626評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮态鳖,結(jié)果婚禮上转培,老公的妹妹穿的比我還像新娘。我一直安慰自己浆竭,他們只是感情好浸须,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,625評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著邦泄,像睡著了一般删窒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上顺囊,一...
    開封第一講書人閱讀 52,255評(píng)論 1 308
  • 那天肌索,我揣著相機(jī)與錄音,去河邊找鬼包蓝。 笑死驶社,一個(gè)胖子當(dāng)著我的面吹牛企量,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播亡电,決...
    沈念sama閱讀 40,825評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼届巩,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了份乒?” 一聲冷哼從身側(cè)響起恕汇,我...
    開封第一講書人閱讀 39,729評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎或辖,沒想到半個(gè)月后瘾英,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,271評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡颂暇,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,363評(píng)論 3 340
  • 正文 我和宋清朗相戀三年缺谴,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片耳鸯。...
    茶點(diǎn)故事閱讀 40,498評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡湿蛔,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出县爬,到底是詐尸還是另有隱情阳啥,我是刑警寧澤,帶...
    沈念sama閱讀 36,183評(píng)論 5 350
  • 正文 年R本政府宣布财喳,位于F島的核電站察迟,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏耳高。R本人自食惡果不足惜扎瓶,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,867評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望祝高。 院中可真熱鬧栗弟,春花似錦、人聲如沸工闺。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽陆蟆。三九已至雷厂,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間叠殷,已是汗流浹背改鲫。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人像棘。 一個(gè)月前我還...
    沈念sama閱讀 48,906評(píng)論 3 376
  • 正文 我出身青樓稽亏,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親缕题。 傳聞我的和親對(duì)象是個(gè)殘疾皇子截歉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,507評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • Run loop 剖析:Runloop 接收的輸入事件來自兩種不同的源:輸入源(intput source)和定時(shí)...
    Mitchell閱讀 12,438評(píng)論 17 111
  • 一、什么是runloop 字面意思是“消息循環(huán)烟零、運(yùn)行循環(huán)”瘪松。它不是線程,但它和線程息息相關(guān)锨阿。一般來講宵睦,一個(gè)線程一次...
    WeiHing閱讀 8,148評(píng)論 11 111
  • 前言 最近離職了,可以盡情熬夜寫點(diǎn)總結(jié),不用擔(dān)心第二天上班爽并蛋疼著墅诡,這篇的主角 RunLoop 一座大山壳嚎,涵蓋的...
    zerocc2014閱讀 12,378評(píng)論 13 67
  • ??昨天找一個(gè)高中同學(xué)聊了一會(huì)天,說了說雙方最近的狀態(tài)书斜。目前他進(jìn)了一家類似外企的企業(yè)诬辈,工資也還算可以,可是每天的生...
    張中華閱讀 159評(píng)論 3 0