RunLoop理解?

  • 版權(quán)聲明:本文為博主原創(chuàng)文章,未經(jīng)博主允許不得轉(zhuǎn)載。

一. Runloop的基本知識(shí)

1. 概念
Runloop是運(yùn)動(dòng)循環(huán),不斷跑圈,無限循環(huán).
RunLoop 是 iOS 和 OSX 開發(fā)中非?;A(chǔ)的一個(gè)概念,這篇文章將從 CFRunLoop 的源碼入手,介紹 RunLoop 的概念以及底層實(shí)現(xiàn)原理。之后會(huì)介紹一下在 iOS 中,蘋果是如何利用 RunLoop 實(shí)現(xiàn)自動(dòng)釋放池、延遲回調(diào)、觸摸事件、屏幕刷新等功能的。
  • 作用:
保持程序的持續(xù)運(yùn)行 (iOS程序一直活著的原因)

處理App中的各種事件(eg:觸摸事件/定時(shí)器事件/selector事件[選擇器·performSelector···])

節(jié)省CPU資源,提高程序的性能(有事做事,沒事休息)

程序已啟動(dòng),就開啟了一個(gè)runloop無限循環(huán),因此程序才能持續(xù)的運(yùn)行
2.RunLoop對(duì)象
  1. 在iOS開發(fā)中有兩套api來訪問Runloop
    Foundation框架 [NSRunloop](OC)

    Core Foundation框架 [CFRunloopRef](C)```

2. NSRunLoop和CFRunLoopRef都代表著RunLoop對(duì)象,它們是等價(jià)的,可以互相轉(zhuǎn)換

3. NSRunLoop是基于CFRunLoopRef的一層OC包裝,所以要了解RunLoop內(nèi)部結(jié)構(gòu),需要多研究CFRunLoopRef層面的API(Core Foundation層面)


######3.Runloop與線程的關(guān)系

1.Runloop和線程的關(guān)系:一個(gè)Runloop對(duì)應(yīng)著一條唯一的線程

    問題:如何讓子線程不死

    回答:給這條子線程開啟一個(gè)Runloop

2.Runloop的創(chuàng)建:主線程Runloop已經(jīng)創(chuàng)建好了,子線程的runloop需要手動(dòng)創(chuàng)建

3.Runloop的生命周期:在第一次獲取時(shí)創(chuàng)建,在線程結(jié)束時(shí)銷毀

###二. Runloop對(duì)象的創(chuàng)建

1. Foundation框架\[NSRunloop]創(chuàng)建Runloop對(duì)象
// 獲取當(dāng)前線程下的Runloop, 懶加載的形式創(chuàng)建
 NSRunLoop * runloop1 = [NSRunLoop currentRunLoop];
// 獲取主線程下的Runloop
NSRunLoop * runloop1 = [NSRunLoop mainRunLoop];```
  1. Core Foundation框架[CFRunloopRef]創(chuàng)建Runloop對(duì)象
    // 獲取當(dāng)前線程下的Runloop, 懶加載的形式創(chuàng)建
    CFRunLoopRef runloop2 = CFRunLoopGetCurrent();
    // 獲取主線程下的Runloop
    CFRunLoopRef runloop2 = CFRunLoopGetMain();```

3. Runloop運(yùn)行原理圖
![圖片來自官網(wǎng)](http://upload-images.jianshu.io/upload_images/838345-faae7ec4a5fb10db.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


4.Runloop相關(guān)的類

CFRunLoopRef

CFRunloopModeRef [Runloop的運(yùn)行模式]

CFRunloopSourceRef [Runloop要處理的事件源]

CFRunloopTimerRef [Timer事件]

CFRunloopObserverRef [Runloop的觀察者(監(jiān)聽者)]```
Runloop要想跑起來,它的內(nèi)部必須要有一個(gè)mode,mode中必須有source/observer/time,至少要有其中的一個(gè).

5.CFRunloopModeRef [Runloop的五個(gè)運(yùn)行模式]

    Runloop每次啟動(dòng)的時(shí)候只能指定一個(gè)運(yùn)行模型,切換模式時(shí)必須退出當(dāng)前的Runloop,再重新進(jìn)入一個(gè)mode,是為了分割不同組的定時(shí)器互不影響

    kCFRunLoopDefaultMode:App的默認(rèn)Mode,通常主線程是在這個(gè)Mode下運(yùn)行

    UITrackingRunLoopMode:界面跟蹤 Mode,用于 ScrollView 追蹤觸摸滑動(dòng),保證界面滑動(dòng)時(shí)不受其他 Mode 影響

    UIInitializationRunLoopMode: 在剛啟動(dòng) App 時(shí)第進(jìn)入的第一個(gè) Mode,啟動(dòng)完成后就不再使用

    GSEventReceiveRunLoopMode: 接受系統(tǒng)事件的內(nèi)部 Mode,通常用不到

    kCFRunLoopCommonModes: 這是一個(gè)占位用的Mode,不是一種真正的Mode

6.CFRunloopTimerRef [Timer事件]

  • 1.Timer事件


  • 2.GCD定時(shí)器
    GCD定時(shí)器必須必須保存起來才能使用
    - (void)gcdTimer
    {
     NSLog(@"+++++++++");
     // 1.創(chuàng)建定時(shí)器
     dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));
     
     // 2.設(shè)置定時(shí)器
     /*
         第一個(gè)參數(shù):定時(shí)器
         第二個(gè)參數(shù):從哪個(gè)時(shí)間開始
         第三個(gè)參數(shù):間隔時(shí)間
         第四個(gè)參數(shù):精確度, 0代表無誤差
         */
        dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 2.0 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
     
     // 3.定時(shí)器觸發(fā)事件
        dispatch_source_set_event_handler(timer, ^{
     NSLog(@"----------");
     });
     
     // 4.開啟定時(shí)器
        dispatch_resume(timer);
     
     // GCD定時(shí)器創(chuàng)建是個(gè)局部變量需要保存才能執(zhí)行
        self.timer = timer;
    }```


- 3.CFRunloopSourceRef [Runloop要處理的事件源]

(1)以前的分法
```swift
Port-Based Sources

Custom Input Sources

Cocoa Perform Selector Sources```


(2)現(xiàn)在的分法

```swift
Source0:非基于Port的 (用戶觸發(fā)的時(shí)間)

Source1:基于Port的 (通過內(nèi)核和其它線程相互發(fā)送消息)```


- 4.CFRunloopObserverRef [Runloop的觀察者 (監(jiān)聽者)]
![](http://upload-images.jianshu.io/upload_images/838345-f15d99e192b2398a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
注意:
![](http://upload-images.jianshu.io/upload_images/838345-5ed898f1141c64c7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)



- 5.Runloop運(yùn)行邏輯
![](http://upload-images.jianshu.io/upload_images/838345-0e9a4fa01684f71d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![](http://upload-images.jianshu.io/upload_images/838345-a917e5bd50943a4c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


###iOS中的RunLoop

>Runloop是事件接收和分發(fā)機(jī)制的一個(gè)實(shí)現(xiàn)。

    Runloop提供了一種異步執(zhí)行代碼的機(jī)制,不能并行執(zhí)行任務(wù)。

    在主隊(duì)列中,Main RunLoop直接配合任務(wù)的執(zhí)行,負(fù)責(zé)處理UI事件、定時(shí)器以及其他內(nèi)核相關(guān)事件。

>RunLoop的主要目的:

    保證程序執(zhí)行的線程不會(huì)被系統(tǒng)終止。   

>什么時(shí)候使用RunLoop ?

    當(dāng)需要和該線程進(jìn)行交互的時(shí)候才會(huì)使用Runloop.

    每一個(gè)線程都有其對(duì)應(yīng)的RunLoop,但是默認(rèn)非主線程的RunLoop是沒有運(yùn)行的,需要為RunLoop添加至少一個(gè)事件源,然后去run它。

    一般情況下我們是沒有必要去啟用線程的RunLoop的,除非你在一個(gè)單獨(dú)的線程中需要長(zhǎng)久的檢測(cè)某個(gè)事件。

    主線程??默認(rèn)有Runloop。當(dāng)自己?jiǎn)?dòng)一個(gè)線程,如果只是用于處理單一的事件,則該線程在執(zhí)行完之后就退出了。所以當(dāng)我們需要讓該線程監(jiān)聽某項(xiàng)事務(wù)時(shí),就得讓線程一直不退出,runloop就是這么一個(gè)循環(huán),沒有事件的時(shí)候,一直卡著,有事件來臨了,執(zhí)行其對(duì)應(yīng)的函數(shù)。

    Runloop,正如其名所示,是線程進(jìn)入和被線程用來響應(yīng)事件以及調(diào)用事件處理函數(shù)的地方。需要在代碼中使用控制語句實(shí)現(xiàn)run loop的循環(huán),也就是說,需要代碼提供while 或者 for循環(huán)來驅(qū)動(dòng)run loop。

    在這個(gè)循環(huán)中,使用一個(gè)Runloop對(duì)象[NSRunloop currentRunloop]執(zhí)行接收消息,調(diào)用對(duì)應(yīng)的處理函數(shù)。

    Runloop接收兩種源事件:input sources和timer sources。

    input sources 傳遞異步事件,通常是來自其他線程和不同的程序中的消息;

    timer sources(定時(shí)器) 傳遞同步事件(重復(fù)執(zhí)行或者在特定時(shí)間上觸發(fā))。

    除了處理input sources,Runloop 也會(huì)產(chǎn)生一些關(guān)于本身行為的notificaiton。注冊(cè)成為Runloop的observer,可以接收到這些notification,做一些額外的處理。(使用CoreFoundation來成為runloop的observer)。

>Runloop工作的特點(diǎn):

    1> 當(dāng)有事件發(fā)生時(shí),Runloop會(huì)根據(jù)具體的事件類型通知應(yīng)用程序作出響應(yīng);

    2> 當(dāng)沒有事件發(fā)生時(shí),Runloop會(huì)進(jìn)入休眠狀態(tài),從而達(dá)到省電的目的;

    3> 當(dāng)事件再次發(fā)生時(shí),Runloop會(huì)被重新喚醒,處理事件。

>提示:一般在開發(fā)中很少會(huì)主動(dòng)創(chuàng)建Runloop,而通常會(huì)把事件添加到Runloop中。

####參考:
[官方文檔](https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Multithreading/RunLoopManagement/RunLoopManagement.html#//apple_ref/doc/uid/10000057i-CH16-SW47)
[深入理解RunLoop](http://blog.ibireme.com/2015/05/18/runloop/)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容