作用(作用重大)
保持程序的持續(xù)運行--內(nèi)部就是do-while循環(huán),在這個循環(huán)內(nèi)部不斷地處理各種任務(wù)
(比如Source、Timer囱修、Observer)
處理app中的各種事件(比如觸摸事件外傅、定時器事件【NSTimer】、selector事件
【選擇器·performSelector···】)
節(jié)省CPU資源荒勇,提高程序性能,有事情就做事情闻坚,沒事情就休息
重要說明
Runloop是程序一直存在并不斷處理事件的原因
main函數(shù)中的Runloop
a. 在UIApplication函數(shù)內(nèi)部就啟動了一個Runloop 該函數(shù)返回一個int類型的值
b. 默認(rèn)啟動的Runloop是跟主線程相關(guān)聯(lián)的
Runloop對象
在iOS開發(fā)中有兩套api來訪問Runloop
a. foundation框架【NSRunloop】
b. core foundation框架【CFRunloopRef】
c. NSRunLoop和CFRunLoopRef都代表著RunLoop對象,它們是等價的沽翔,可以互相轉(zhuǎn)換
d. NSRunLoop是基于CFRunLoopRef的一層OC包裝,所以要了解RunLoop內(nèi)部結(jié)構(gòu)窿凤,需要多研究
CFRunLoopRef層面的API(Core Foundation層面)
Runloop與線程
Runloop和線程的關(guān)系:一個Runloop對應(yīng)著一條唯一的線程仅偎,一條線程最多有一個Runloop西潘;開啟一個Runloop能讓子線程不死
Runloop的創(chuàng)建:主線程Runloop已經(jīng)創(chuàng)建好了,子線程的runloop需要手動創(chuàng)建并開啟
Runloop的生命周期:在第一次獲取時創(chuàng)建哨颂,在線程結(jié)束時銷毀
獲得Runloop對象
1.獲得當(dāng)前Runloop對象
//01 NSRunloop
NSRunLoop * runloop1 = [NSRunLoop currentRunLoop];
//02 CFRunLoopRef
CFRunLoopRef runloop2 =? CFRunLoopGetCurrent();
?
2.拿到當(dāng)前應(yīng)用程序的主Runloop(主線程對應(yīng)的Runloop)
//01 NSRunloop
NSRunLoop * runloop1 = [NSRunLoop mainRunLoop];
//02 CFRunLoopRef
CFRunLoopRef runloop2 =? CFRunLoopGetMain();
?
/*3.注意點:開一個子線程創(chuàng)建runloop,不是通過alloc init方法創(chuàng)建喷市,而是直接通過調(diào)用
currentRunLoop方法來創(chuàng)建,它本身是一個懶加載的威恼。如果不存在那么會自動創(chuàng)建一個該線程
對應(yīng)的runloop對象返回
4.在子線程中品姓,如果不主動獲取Runloop的話,那么子線程內(nèi)部是不會創(chuàng)建Runloop的箫措「贡福可以下載
CFRunloopRef的源碼,搜索_CFRunloopGet0,查看代碼斤蔓。
5.Runloop對象是利用字典來進行存儲植酥,而且key是對應(yīng)的線程Value為該線程對應(yīng)的Runloop。
*/
基本應(yīng)用
/*
1)開啟NSTimer弦牡,控制定時器在特定模式下執(zhí)行
2)可以讓某些事件(行為友驮、任務(wù))在特定模式下執(zhí)行,如ImageView顯示:控制方法在特定的模式下可用
3)PerformSelector:控制線程執(zhí)行不同的任務(wù)
4)常駐線程:讓一個子線程不進入消亡狀態(tài)驾锰,等待其他線程發(fā)來消息卸留,處理其他事件
5)可以添加Observer監(jiān)聽RunLoop的狀態(tài),比如監(jiān)聽點擊事件的處理(在所有點擊事件之前做一些事情
6)自動釋放池(可通過Observer監(jiān)聽RunLoop的狀態(tài))
第一次創(chuàng)建:進入runloop的時候
最后一次釋放:runloop退出的時候
其它創(chuàng)建和釋放:當(dāng)runloop即將休眠的時候會把之前的自動釋放池釋放椭豫,然后重新創(chuàng)建一個新的釋放池
?
常駐線程實現(xiàn):
主線程對應(yīng)的runloop默認(rèn)已經(jīng)創(chuàng)建好了,但是子線程對應(yīng)的runloop需要手動創(chuàng)建
子線程對應(yīng)的runloop還需要手動的開啟耻瑟,否則該runloop一創(chuàng)建出來就退出;在開啟前要先添加事件赏酥,否則也會退出喳整。
保證mode里面有事件,不讓runloop立刻退出
可以往runloop中添加source和timer,但是添加observer是沒有作用的
*/
/*
NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(timer) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
*/
?
//創(chuàng)建子線程對應(yīng)的runloop并添加基于port的source
[[NSRunLoop currentRunLoop]addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
?
//開啟runloop,運行在默認(rèn)模式下面(添加timer或是port都要開始runloop)
[[NSRunLoop currentRunLoop]run];
請簡單說明runloop中幾個類之間的相互關(guān)系(runloop & source & timer &observer &mode)
a.CFRunloopRef
b.CFRunloopModeRef【Runloop的運行模式】
c.CFRunloopSourceRef【Runloop要處理的事件源】
d.CFRunloopTimerRef【Timer事件】
e.CFRunloopObserverRef【Runloop的觀察者(監(jiān)聽者)】
1.runloop啟動之后會選擇一種運行模式,在執(zhí)行執(zhí)行會先檢查運行模式內(nèi)部是否有source和timers,如果一個sourc或者是一個timer都沒有那么runlooop啟動之后就立刻退出了裸扶。
2.runlooop的source有兩種分類方法
按照以前的分類方法可以分為: 基于端口的? 自定義的? performSelector事件
按照函數(shù)調(diào)用棧來劃分:? source0? soucrce1
3.observer框都,可以用來監(jiān)聽當(dāng)前runloop運行狀態(tài)的改變,注意(Core foundation框架)
4.NSTimer必須添加到runloop中才會工作姓言,且其工作收到runloop運行模式的影響瞬项。defultMode? UItrackingMode
什么時候使用run loop
僅當(dāng)在為你的程序創(chuàng)建輔助線程的時候,你才需要顯式運行一個run loop何荚。Run loop是程序主線程基礎(chǔ)設(shè)施的關(guān)鍵部分。所以猪杭,Cocoa和Carbon程序提供了代碼運行主程序的循環(huán)并自動啟動run loop餐塘。IOS程序中UIApplication的run方法(或Mac OS X中的NSApplication)作為程序啟動步驟的一部分,它在程序正常啟動的時候就會啟動程序的主循環(huán)皂吮。類似的戒傻,RunApplicationEventLoop函數(shù)為Carbon程序啟動主循環(huán)税手。如果你使用xcode提供的模板創(chuàng)建你的程序,那你永遠(yuǎn)不需要自己去顯式的調(diào)用這些例程需纳。
對于輔助線程芦倒,你需要判斷一個run loop是否是必須的。如果是必須的不翩,那么你要自己配置并啟動它兵扬。你不需要在任何情況下都去啟動一個線程的run loop。比如口蝠,你使用線程來處理一個預(yù)先定義的長時間運行的任務(wù)時器钟,你應(yīng)該避免啟動run loop。Run loop在你要和線程有更多的交互時才需要妙蔗,比如以下情況:
使用端口或自定義輸入源來和其他線程通信
使用線程的定時器
Cocoa中使用任何performSelector…的方法
使線程周期性工作