iOS開發(fā)-RunLoop的介紹

RunLoop簡單介紹

  • RunLoop(運行循環(huán))的作用

    • 保持程序的持續(xù)運行(ios程序為什么能一直活著不會死)
    • 處理app中的各種事件(比如觸摸事件蚂四、定時器事件(NSTimer)、selector事件(performSelector)
    • 節(jié)省CPU資源就轧,提高程序性能证杭,有事情就做事情,沒事情就休息
  • 如果沒有Runloop,那么程序一啟動,函數(shù)main一執(zhí)行完,程序就會退出妒御,那么應(yīng)用程序就什么都做不了解愤。

  • Runloop就相當(dāng)于一個死循環(huán),在應(yīng)用程序的運行過程中保證運用程序的不死.

  • 那么保持運用程序持續(xù)運行的RunLoop是在什么地方開啟的呢?它是在main函數(shù)中的UIApplicationMain中啟動的.所以main函數(shù)就一直沒有返回值,程序就會一直運行.這個默認啟動的RunLoop是跟主線程相關(guān)聯(lián)的.

  • RunLoop與線程的關(guān)系

    • 一個RunLoop對應(yīng)著一個線程,如果你想開啟一條常駐線程(不死線程),可以在子線程中開啟一個對應(yīng)的RunLoop就可以實現(xiàn)了.
    • RunLoop的創(chuàng)建:主線程Runloop系統(tǒng)已經(jīng)創(chuàng)建好了,子線程的runloop需要手動創(chuàng)建
    • RunLoop的聲明周期:在第一次獲取RunLoop的時候創(chuàng)建,在線程結(jié)束的時候銷毀.

RunLoop的對象

  • 在iOS開發(fā)中有兩套api來訪問Runloop
    • foundation框架【NSRunloop】
    • core foundation框架【CFRunloopRef】
  • NSRunLoop和CFRunLoopRef都代表著RunLoop對象,它們是等價的乎莉,可以互相轉(zhuǎn)換
  • NSRunLoop是基于CFRunLoopRef的一層OC包裝送讲,所以要了解RunLoop內(nèi)部結(jié)構(gòu),需要多研究CFRunLoopRef層面的API(Core Foundation層面)
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    //獲得當(dāng)前線程對應(yīng)的RunLoop
    NSRunLoop *currentRunLoop = [NSRunLoop currentRunLoop];
    
    //獲取主線程的RunLoop
    NSRunLoop *mainRunLoop = [NSRunLoop mainRunLoop];
    
    NSLog(@"%@----%p", currentRunLoop, mainRunLoop);
    
    
    //當(dāng)前的RunLoop
    CFRunLoopRef current = CFRunLoopGetCurrent();
    
    //主線程對應(yīng)的RunLoop
    CFRunLoopRef main = CFRunLoopGetMain();
    
    //不同的語言環(huán)境下同一對象的地址不同
    NSLog(@"%p-----%p", current, main);
    
    //轉(zhuǎn)換
    NSLog(@"%p", mainRunLoop.getCFRunLoop);
    
    
    //子線程的RunLoop
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(task) object:nil];
    [thread start];
}


- (void)task
{
    NSLog(@"%@", [NSThread currentThread]);
    
    
    //子線程的runloop如何獲得
    //主線程對應(yīng)的runloop默認已經(jīng)開啟了,但是子線程的runloop需要我們主動去創(chuàng)建
    NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
    NSLog(@"%p----%p",runLoop, [NSRunLoop currentRunLoop]);
}

上面的注意點:
1.開一個子線程創(chuàng)建runloop,不是通過alloc init方法創(chuàng)建惋啃,而是直接通過調(diào)用currentRunLoop方法來創(chuàng)建哼鬓,它本身是一個懶加載的。
2.在子線程中边灭,如果不主動獲取Runloop的話异希,那么子線程內(nèi)部是不會創(chuàng)建Runloop的。

Runloop相關(guān)類

  • 五個相關(guān)的類
    a.CFRunloopRef
    b.CFRunloopModeRef【Runloop的運行模式】
    c.CFRunloopSourceRef【Runloop要處理的事件源】
    d.CFRunloopTimerRef【Timer事件】
    e.CFRunloopObserverRef【Runloop的觀察者(監(jiān)聽者)】
  • Runloop運行原理圖
Snip20160408_21.png
  • Runloop和相關(guān)類之間的關(guān)系圖
Snip20160408_22.png
  • CFRunloopModeRef
    Runloop要想跑起來绒瘦,它的內(nèi)部必須要有一個mode,這個mode里面必須有source\observer\timer称簿,至少要有其中的一個扣癣。
    01.CFRunloopModeRef代表著Runloop的運行模式
    02.一個Runloop中可以有多個mode,一個mode里面又可以有多個source\observer\timer等等
    03.每次runloop啟動的時候,只能指定一個mode,這個mode被稱為該Runloop的當(dāng)前mode
    04.如果需要切換mode,只能先退出當(dāng)前Runloop,再重新指定一個mode進入
    05.這樣做主要是為了分割不同組的定時器等憨降,讓他們相互之間不受影響
    06.系統(tǒng)默認注冊了5個mode
    a.kCFRunLoopDefaultMode:App的默認Mode父虑,通常主線程是在這個Mode下運行--kCFRunLoopDefaultMode ==== NSDefaultRunLoopMode
    b.UITrackingRunLoopMode:界面跟蹤 Mode,用于 ScrollView 追蹤觸摸滑動授药,保證界面滑動時不受其他 Mode 影響
    c.UIInitializationRunLoopMode: 在剛啟動 App 時第進入的第一個 Mode士嚎,啟動完成后就不再使用
    d.GSEventReceiveRunLoopMode: 接受系統(tǒng)事件的內(nèi)部 Mode,通常用不到
    e.kCFRunLoopCommonModes: 這是一個占位用的Mode悔叽,不是一種真正的Mode---NSRunLoopCommonModes

  • CFRunloopTimerRef
    1.NSTimer相關(guān)代碼

            /*
                說明:
                (1)runloop一啟動就會選中一種模式莱衩,當(dāng)選中了一種模式之后其它的模式就都不鳥。一個mode里面可以添加多個NSTimer,也就是說以后當(dāng)創(chuàng)建NSTimer的時候骄蝇,可以指定它是在什么模式下運行的膳殷。
                (2)它是基于時間的觸發(fā)器,說直白點那就是時間到了我就觸發(fā)一個事件九火,觸發(fā)一個操作赚窃。基本上說的就是NSTimer
                (3)相關(guān)代碼
            */
            - (void)timer2
            {
                //NSTimer 調(diào)用了scheduledTimer方法岔激,那么會自動添加到當(dāng)前的runloop里面去勒极,而且runloop的運行模式kCFRunLoopDefaultMode

                NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];

                //更改模式
                [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

            }

            - (void)timer1
            {
                //    [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];

                NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];

                //定時器添加到UITrackingRunLoopMode模式,一旦runloop切換模式虑鼎,那么定時器就不工作
                //    [[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];

                //定時器添加到NSDefaultRunLoopMode模式辱匿,一旦runloop切換模式,那么定時器就不工作
                //    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];

                //占位模式:common modes標記
                //被標記為common modes的模式 kCFRunLoopDefaultMode  UITrackingRunLoopMode
                [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

                //    NSLog(@"%@",[NSRunLoop currentRunLoop]);
            }

            - (void)run
            {
                NSLog(@"---run---%@",[NSRunLoop currentRunLoop].currentMode);
            }

            - (IBAction)btnClick {

                NSLog(@"---btnClick---");
            }

2.GCD中的定時器

           //0.創(chuàng)建一個隊列
            dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
            //1.創(chuàng)建一個GCD的定時器
            /*
             第一個參數(shù):說明這是一個定時器
             第四個參數(shù):GCD的回調(diào)任務(wù)添加到那個隊列中執(zhí)行炫彩,如果是主隊列則在主線程執(zhí)行
             */
            dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
            //2.設(shè)置定時器的開始時間匾七,間隔時間以及精準度
            //設(shè)置開始時間,三秒鐘之后調(diào)用
            dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW,3.0 *NSEC_PER_SEC);
            //設(shè)置定時器工作的間隔時間
            uint64_t intevel = 1.0 * NSEC_PER_SEC;
            /*
             第一個參數(shù):要給哪個定時器設(shè)置
             第二個參數(shù):定時器的開始時間DISPATCH_TIME_NOW表示從當(dāng)前開始
             第三個參數(shù):定時器調(diào)用方法的間隔時間
             第四個參數(shù):定時器的精準度江兢,如果傳0則表示采用最精準的方式計算昨忆,如果傳大于0的數(shù)值,則表示該定時切換i可以接收該值范圍內(nèi)的誤差杉允,通常傳0
             該參數(shù)的意義:可以適當(dāng)?shù)奶岣叱绦虻男阅?             注意點:GCD定時器中的時間以納秒為單位(面試)
             */
            dispatch_source_set_timer(timer, start, intevel, 0 * NSEC_PER_SEC);
            //3.設(shè)置定時器開啟后回調(diào)的方法
            /*
             第一個參數(shù):要給哪個定時器設(shè)置
             第二個參數(shù):回調(diào)block
             */
            dispatch_source_set_event_handler(timer, ^{
                NSLog(@"------%@",[NSThread currentThread]);
            });
            //4.執(zhí)行定時器
            dispatch_resume(timer);
            //注意:dispatch_source_t本質(zhì)上是OC類邑贴,在這里是個局部變量,需要強引用
            self.timer = timer;
            GCD定時器補充
            /*
             DISPATCH_SOURCE_TYPE_TIMER         定時響應(yīng)(定時器事件)
             DISPATCH_SOURCE_TYPE_SIGNAL        接收到UNIX信號時響應(yīng)
             DISPATCH_SOURCE_TYPE_READ          IO操作叔磷,如對文件的操作拢驾、socket操作的讀響應(yīng)
             DISPATCH_SOURCE_TYPE_WRITE         IO操作,如對文件的操作改基、socket操作的寫響應(yīng)
             DISPATCH_SOURCE_TYPE_VNODE         文件狀態(tài)監(jiān)聽繁疤,文件被刪除、移動、重命名
             DISPATCH_SOURCE_TYPE_PROC          進程監(jiān)聽,如進程的退出嵌洼、創(chuàng)建一個或更多的子線程案疲、進程收到UNIX信號
             下面兩個都屬于Mach相關(guān)事件響應(yīng)
                DISPATCH_SOURCE_TYPE_MACH_SEND
                DISPATCH_SOURCE_TYPE_MACH_RECV
             下面兩個都屬于自定義的事件,并且也是有自己來觸發(fā)
                DISPATCH_SOURCE_TYPE_DATA_ADD
                DISPATCH_SOURCE_TYPE_DATA_OR
             */
  • CFRunloopSourceRef
    1.是事件源也就是輸入源麻养,有兩種分類模式;
    a.一種是按照蘋果官方文檔進行劃分的
    b.另一種是基于函數(shù)的調(diào)用棧來進行劃分的(source0和source1)

  • CFRunLoopObserverRef
    1.CFRunLoopObserverRef是觀察者诺舔,能夠監(jiān)聽RunLoop的狀態(tài)改變
    2.如何監(jiān)聽

 //創(chuàng)建一個runloop監(jiān)聽者
CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(),kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {

     NSLog(@"監(jiān)聽runloop狀態(tài)改變---%zd",activity);
});

  //為runloop添加一個監(jiān)聽者
  CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer,     kCFRunLoopDefaultMode);
  //釋放監(jiān)聽者
  CFRelease(observer)

3.監(jiān)聽的狀態(tài)

typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
                kCFRunLoopEntry = (1UL << 0),   //即將進入Runloop
                kCFRunLoopBeforeTimers = (1UL << 1),    //即將處理NSTimer
                kCFRunLoopBeforeSources = (1UL << 2),   //即將處理Sources
                kCFRunLoopBeforeWaiting = (1UL << 5),   //即將進入休眠
                kCFRunLoopAfterWaiting = (1UL << 6),    //剛從休眠中喚醒
                kCFRunLoopExit = (1UL << 7),            //即將退出runloop
                kCFRunLoopAllActivities = 0x0FFFFFFFU   //所有狀態(tài)改變
            };

RunLoop邏輯處理

Snip20160408_23.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末鳖昌,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子低飒,更是在濱河造成了極大的恐慌许昨,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件褥赊,死亡現(xiàn)場離奇詭異糕档,居然都是意外死亡,警方通過查閱死者的電腦和手機拌喉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門速那,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人尿背,你說我怎么就攤上這事端仰。” “怎么了田藐?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵荔烧,是天一觀的道長。 經(jīng)常有香客問我汽久,道長鹤竭,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任景醇,我火速辦了婚禮臀稚,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘啡直。我一直安慰自己烁涌,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布酒觅。 她就那樣靜靜地躺著撮执,像睡著了一般。 火紅的嫁衣襯著肌膚如雪舷丹。 梳的紋絲不亂的頭發(fā)上抒钱,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天,我揣著相機與錄音,去河邊找鬼谋币。 笑死菩帝,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的线定。 我是一名探鬼主播罗岖,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼诅蝶!你這毒婦竟也來了退个?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤调炬,失蹤者是張志新(化名)和其女友劉穎语盈,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體缰泡,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡刀荒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了棘钞。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片缠借。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖武翎,靈堂內(nèi)的尸體忽然破棺而出烈炭,到底是詐尸還是另有隱情,我是刑警寧澤宝恶,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布符隙,位于F島的核電站,受9級特大地震影響垫毙,放射性物質(zhì)發(fā)生泄漏霹疫。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一综芥、第九天 我趴在偏房一處隱蔽的房頂上張望丽蝎。 院中可真熱鬧,春花似錦膀藐、人聲如沸屠阻。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽国觉。三九已至,卻和暖如春虾啦,著一層夾襖步出監(jiān)牢的瞬間麻诀,已是汗流浹背痕寓。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蝇闭,地道東北人呻率。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像呻引,于是被迫代替她去往敵國和親礼仗。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,901評論 2 345

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

  • Run loop 剖析:Runloop 接收的輸入事件來自兩種不同的源:輸入源(intput source)和定時...
    Mitchell閱讀 12,411評論 17 111
  • 先貼下 apple doc, 本文基本是對照 doc 的翻譯:https://developer.apple.co...
    brownfeng閱讀 6,849評論 8 111
  • RunLoop的基本了解 **1 . RunLoop字面的意思 : **運行循環(huán) / 跑圈 **2 . 基本作用 ...
    Mario_ZJ閱讀 505評論 1 3
  • runtime 和 runloop 作為一個程序員進階是必須的逻悠,也是非常重要的藐守, 在面試過程中是經(jīng)常會被問到的, ...
    SOI閱讀 21,780評論 3 63
  • Runloop是iOS和OSX開發(fā)中非初宸纾基礎(chǔ)的一個概念,從概念開始學(xué)習(xí)乾蓬。 RunLoop的概念 -般說惠啄,一個線程一...
    小貓仔閱讀 979評論 0 1