runloop學(xué)習(xí)記錄

1.runloop源碼

源碼

Snip20180407_10.png


2.對象介紹

image.png

接下來的對象介紹,可以借助這個(gè)圖理清對象間的關(guān)系

// 一個(gè)runloop對象
typedef struct __CFRunLoop * CFRunLoopRef;
// source
typedef struct __CFRunLoopSource * CFRunLoopSourceRef;
// observer觀察者
typedef struct __CFRunLoopObserver * CFRunLoopObserverRef;
// timer
typedef struct __CFRunLoopTimer * CFRunLoopTimerRef;
// mode
typedef struct __CFRunLoopMode *CFRunLoopModeRef;

2.1. CFRunLoopRef

一個(gè)指向__CFRunLoop結(jié)構(gòu)體的指針

struct __CFRunLoop {
    CFRuntimeBase _base;
    pthread_mutex_t _lock;          /* locked for accessing mode list */
    __CFPort _wakeUpPort;           // used for CFRunLoopWakeUp 
    Boolean _unused;
    volatile _per_run_data *_perRunData;              // reset for runs of the run loop
    pthread_t _pthread;
    uint32_t _winthread;
    CFMutableSetRef _commonModes;
    CFMutableSetRef _commonModeItems;
    CFRunLoopModeRef _currentMode;
    CFMutableSetRef _modes;
    struct _block_item *_blocks_head;
    struct _block_item *_blocks_tail;
    CFTypeRef _counterpart;
};

從這個(gè)結(jié)構(gòu)體的內(nèi)容可以看出:

  • 一個(gè)runloop對象主要包含modes沥曹、線程
  • modes是一個(gè)可變集合被碗,里面存著mode藻肄,所以一個(gè)runloop對象可以包含多個(gè)mode
  • 一個(gè) RunLoop 包含若干個(gè) Mode木柬,每個(gè) Mode 又包含若干個(gè) Source/Timer/Observer缰雇。(這三個(gè)的概念后面講)入偷。每次調(diào)用 RunLoop 的主函數(shù)時(shí),只能指定其中一個(gè) Mode寓涨,這個(gè)Mode被稱作 CurrentMode盯串。如果需要切換 Mode,只能退出 Loop戒良,再重新指定一個(gè) Mode 進(jìn)入体捏。這樣做主要是為了分隔開不同組的 Source/Timer/Observer,讓其互不影響糯崎。

2.2. CFRunLoopSourceRef

一個(gè)指向__CFRunLoopSource結(jié)構(gòu)體的指針

struct __CFRunLoopSource {
    CFRuntimeBase _base;
    uint32_t _bits;
    pthread_mutex_t _lock;
    CFIndex _order;         /* immutable */
    CFMutableBagRef _runLoops;
    union {
    CFRunLoopSourceContext version0;    /* immutable, except invalidation */
        CFRunLoopSourceContext1 version1;   /* immutable, except invalidation */
    } _context;
};
  • 結(jié)構(gòu)體有一個(gè)_runLoops(可變包對象)几缭,說明一個(gè)source可以添加到多個(gè)runloop中

  • CFRunLoopSourceContext version0

typedef struct {
    CFIndex version;
    void *  info;
    const void *(*retain)(const void *info);
    void    (*release)(const void *info);
    CFStringRef (*copyDescription)(const void *info);
    Boolean (*equal)(const void *info1, const void *info2);
    CFHashCode  (*hash)(const void *info);
    void    (*schedule)(void *info, CFRunLoopRef rl, CFStringRef mode);
    void    (*cancel)(void *info, CFRunLoopRef rl, CFStringRef mode);
    void    (*perform)(void *info);
} CFRunLoopSourceContext;

  • CFRunLoopSourceContext1 version1
typedef struct {
    CFIndex version;
    void *  info;
    const void *(*retain)(const void *info);
    void    (*release)(const void *info);
    CFStringRef (*copyDescription)(const void *info);
    Boolean (*equal)(const void *info1, const void *info2);
    CFHashCode  (*hash)(const void *info);
#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) || (TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)
    mach_port_t (*getPort)(void *info);
    void *  (*perform)(void *msg, CFIndex size, CFAllocatorRef allocator, void *info);
#else
    void *  (*getPort)(void *info);
    void    (*perform)(void *info);
#endif
} CFRunLoopSourceContext1;
  • version0和version1區(qū)別
    當(dāng)我們接受到的消息(source),比如觸摸事件沃呢,滑動事件等等年栓;這個(gè)source是有兩種的,一種是version0薄霜,也就是用source0來表示某抓,一種是version1 -> source1
    區(qū)別
version0 / source0 source0 是非基于 port 的事件,主要是 APP 內(nèi)部事件惰瓜,如點(diǎn)擊事件否副,觸摸事件等
version1 / source1 source1 是基于Port的,通過內(nèi)核和其他線程通信崎坊,接收备禀,分發(fā)系統(tǒng)事件。

2.3. CFRunLoopObserverRef

一個(gè)指向__CFRunLoopObserver結(jié)構(gòu)體的指針
作用:觀察者,觀察runloop的各種狀態(tài)曲尸,并通過回調(diào)拋出去

struct __CFRunLoopObserver {
    CFRuntimeBase _base;
    pthread_mutex_t _lock;
    CFRunLoopRef _runLoop;
    CFIndex _rlCount;
    CFOptionFlags _activities;      /* immutable */
    CFIndex _order;         /* immutable */
    CFRunLoopObserverCallBack _callout; /* immutable */
    CFRunLoopObserverContext _context;  /* immutable, except invalidation */
};

其中的CFOptionFlags是一個(gè)枚舉:表示runloop的狀態(tài)

/* Run Loop Observer Activities */
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
    kCFRunLoopEntry = (1UL << 0),            // 即將進(jìn)入loop
    kCFRunLoopBeforeTimers = (1UL << 1),     // 即將處理timer
    kCFRunLoopBeforeSources = (1UL << 2),    // 即將處理source
    kCFRunLoopBeforeWaiting = (1UL << 5),    // 即將進(jìn)入休眠
    kCFRunLoopAfterWaiting = (1UL << 6),     // 剛從休眠中喚醒
    kCFRunLoopExit = (1UL << 7),             // 即將退出loop
    kCFRunLoopAllActivities = 0x0FFFFFFFU    // 占位
};


CFRunLoopObserverRef觀察者會將觀察到的狀態(tài)變化通過回調(diào)_callout跑出去
看下這個(gè)CFRunLoopObserverCallBack _callout

// 這個(gè)回調(diào)可以將觀察者赋续、runloop狀態(tài)、info傳出去
typedef void (*CFRunLoopObserverCallBack)(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info);

2.4. CFRunLoopTimerRef

是一個(gè)指向__CFRunLoopTimer結(jié)構(gòu)體的指針

某些數(shù)據(jù)類型能夠在Core Foundation和Foundation之間互換使用另患,可被互換使用的數(shù)據(jù)類型被稱為Toll-Free Bridged類型纽乱。

  • CFRunLoopTimerRef 是定時(shí)器,可以在設(shè)定的時(shí)間點(diǎn)拋出回調(diào)
  • CFRunLoopTimerRef和NSTimer是toll-free bridged的柴淘,可以相互轉(zhuǎn)換迫淹。
struct __CFRunLoopTimer {
    CFRuntimeBase _base;
    uint16_t _bits;
    pthread_mutex_t _lock;
    CFRunLoopRef _runLoop;
    CFMutableSetRef _rlModes;
    CFAbsoluteTime _nextFireDate;
    CFTimeInterval _interval;       /* immutable */
    CFTimeInterval _tolerance;          /* mutable */
    uint64_t _fireTSR;          /* TSR units */
    CFIndex _order;         /* immutable */
    CFRunLoopTimerCallBack _callout;    /* immutable */
    CFRunLoopTimerContext _context; /* immutable, except invalidation */
};

2.5.CFRunLoopModeRef

一個(gè)指向__CFRunLoopMode結(jié)構(gòu)體的指針

typedef struct __CFRunLoopMode *CFRunLoopModeRef;

struct __CFRunLoopMode {
    CFRuntimeBase _base;
    pthread_mutex_t _lock;  /* must have the run loop locked before locking this */
    CFStringRef _name;
    Boolean _stopped;
    char _padding[3];
    CFMutableSetRef _sources0;
    CFMutableSetRef _sources1;
    CFMutableArrayRef _observers;
    CFMutableArrayRef _timers;
    CFMutableDictionaryRef _portToV1SourceMap;
    __CFPortSet _portSet;
    CFIndex _observerMask;
#if USE_DISPATCH_SOURCE_FOR_TIMERS
    dispatch_source_t _timerSource;
    dispatch_queue_t _queue;
    Boolean _timerFired; // set to true by the source when a timer has fired
    Boolean _dispatchTimerArmed;
#endif
#if USE_MK_TIMER_TOO
    mach_port_t _timerPort;
    Boolean _mkTimerArmed;
#endif
#if DEPLOYMENT_TARGET_WINDOWS
    DWORD _msgQMask;
    void (*_msgPump)(void);
#endif
    uint64_t _timerSoftDeadline; /* TSR */
    uint64_t _timerHardDeadline; /* TSR */
};

  • _sources0、 _sources1都是可變集合對象为严,對應(yīng)著用來存取CFRunLoopSourceRef對象敛熬,CFRunLoopSourceRef對象中有version0version1分別對應(yīng)著_sources0_sources1
  • 包含了observer第股、timer
  • CFStringRef _name就是mode的名字应民,如:kCFRunLoopDefaultMode
  • 有幾種mode圖片來源
    image.png

3.函數(shù)介紹

3.1.__CFRunLoopDoObservers

通知Observer,runloop要做什么事情
這個(gè)__CFRunLoopDoObservers函數(shù)需要傳三個(gè)參數(shù)夕吻,分別是

  • CFRunLoopRef(runloop對象)
  • CFRunLoopModeRef(runloop的mode)
  • CFRunLoopActivity(runloop的狀態(tài)枚舉)


    這個(gè)函數(shù)的實(shí)現(xiàn)

3.2._CFRunLoopGet0

runloop對象是存在全局字典中的诲锹,key就是pthread_t
這個(gè)_CFRunLoopGet0函數(shù)的作用就是獲取對應(yīng)線程的runloop

實(shí)現(xiàn)思路(依據(jù)就是下面截圖的源碼)
1.先判斷這個(gè)全局字典存不存在,不存在涉馅,創(chuàng)建一個(gè)归园,并將主線程的runloop加進(jìn)去
2.直接去字典里取這個(gè)loop
3.如果loop不存在,就創(chuàng)建一個(gè)loop加入到全局字典中
// 偽代碼
if(!__CFRunLoops) {
      1.創(chuàng)建全局字典
      2.創(chuàng)建主線程loop稚矿,并加入到全局字典中
}
根據(jù)線程pthread_t為key庸诱,去字典取對應(yīng)的loop
if(!loop) {
      1.創(chuàng)建loop
      2.加入到字典中
}
return loop

其實(shí)這個(gè)說明了runloop和線程是一一對應(yīng)的關(guān)系

Snip20180407_22.png

3.3.獲取主線程loop和獲取當(dāng)前的loop

image.png

參考文檔

強(qiáng)力推薦
RunLoop系列之要點(diǎn)提煉
RunLoop系列之源碼分析
iOS刨根問底-深入理解RunLoop
深入理解 RunLoop

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市晤揣,隨后出現(xiàn)的幾起案子桥爽,更是在濱河造成了極大的恐慌,老刑警劉巖昧识,帶你破解...
    沈念sama閱讀 212,080評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件钠四,死亡現(xiàn)場離奇詭異,居然都是意外死亡跪楞,警方通過查閱死者的電腦和手機(jī)缀去,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,422評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來甸祭,“玉大人朵耕,你說我怎么就攤上這事×芤叮” “怎么了?”我有些...
    開封第一講書人閱讀 157,630評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長煞檩。 經(jīng)常有香客問我处嫌,道長,這世上最難降的妖魔是什么斟湃? 我笑而不...
    開封第一講書人閱讀 56,554評論 1 284
  • 正文 為了忘掉前任熏迹,我火速辦了婚禮,結(jié)果婚禮上凝赛,老公的妹妹穿的比我還像新娘注暗。我一直安慰自己,他們只是感情好墓猎,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,662評論 6 386
  • 文/花漫 我一把揭開白布捆昏。 她就那樣靜靜地躺著,像睡著了一般毙沾。 火紅的嫁衣襯著肌膚如雪骗卜。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,856評論 1 290
  • 那天左胞,我揣著相機(jī)與錄音寇仓,去河邊找鬼。 笑死烤宙,一個(gè)胖子當(dāng)著我的面吹牛遍烦,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播躺枕,決...
    沈念sama閱讀 39,014評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼服猪,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了屯远?” 一聲冷哼從身側(cè)響起蔓姚,我...
    開封第一講書人閱讀 37,752評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎慨丐,沒想到半個(gè)月后坡脐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,212評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡房揭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,541評論 2 327
  • 正文 我和宋清朗相戀三年备闲,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片捅暴。...
    茶點(diǎn)故事閱讀 38,687評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡恬砂,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蓬痒,到底是詐尸還是另有隱情泻骤,我是刑警寧澤,帶...
    沈念sama閱讀 34,347評論 4 331
  • 正文 年R本政府宣布,位于F島的核電站狱掂,受9級特大地震影響演痒,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜趋惨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,973評論 3 315
  • 文/蒙蒙 一鸟顺、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧器虾,春花似錦讯嫂、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,777評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至挤悉,卻和暖如春渐裸,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背装悲。 一陣腳步聲響...
    開封第一講書人閱讀 32,006評論 1 266
  • 我被黑心中介騙來泰國打工昏鹃, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人诀诊。 一個(gè)月前我還...
    沈念sama閱讀 46,406評論 2 360
  • 正文 我出身青樓洞渤,卻偏偏與公主長得像,于是被迫代替她去往敵國和親属瓣。 傳聞我的和親對象是個(gè)殘疾皇子载迄,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,576評論 2 349

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

  • 1 Runloop機(jī)制原理 深入理解RunLoop http://www.cocoachina.com/ios/2...
    Kevin_Junbaozi閱讀 3,996評論 4 30
  • RunLoop 的概念 一般來講,一個(gè)線程一次只能執(zhí)行一個(gè)任務(wù)抡蛙,執(zhí)行完成后線程就會退出护昧。如果我們需要一個(gè)機(jī)制,讓線...
    Mirsiter_魏閱讀 617評論 0 2
  • runtime 和 runloop 作為一個(gè)程序員進(jìn)階是必須的粗截,也是非常重要的惋耙, 在面試過程中是經(jīng)常會被問到的, ...
    made_China閱讀 1,204評論 0 7
  • 轉(zhuǎn)載:http://www.cocoachina.com/ios/20150601/11970.html RunL...
    Gatling閱讀 1,436評論 0 13
  • 初中和高中時(shí)總說熊昌,要珍惜身邊每一位朋友绽榛。 那時(shí)的我們,還不知道什么是珍惜婿屹,因?yàn)橐膊恢朗裁词鞘ッ鹈馈ι磉叺娜撕茫?jīng)...
    長亭微雨閱讀 242評論 0 0