RunLoop的使用總結(jié)

1飒箭、介紹RunLoop

什么是RunLoop

//runloop從字面的意思來看就是:跑 - 圈 也就是運(yùn)行循環(huán)狼电。
//以下是runloop的偽代碼。弦蹂。肩碟。
int main(int argc, char * argv[]) {
    BOOL running = YES;
    do {
        //執(zhí)行各種任務(wù),處理事件
    }while (running);
        return 0;
}

基本作用:

  • 保持程序的持續(xù)運(yùn)行凸椿,如果沒有RunLoop削祈,程序執(zhí)行完main函數(shù)就結(jié)束了。
  • 處理App中的各種事件(比如觸摸事件脑漫、定時器事件髓抑、Selector事件)
  • 節(jié)省CPU資源,提高程序性能:該做事時做事窿撬,該休息時休息......

2启昧、RunLoop對象

  • iOS中有2套API來訪問和使用RunLoop
    Foundation框架中的NSRunLoop;
    Core Foundation中的CFRunLoop;

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

3密末、RunLoop與線程

每條線程都有唯一的一個與之對應(yīng)的RunLoop對象
主線程中的RunLoop由系統(tǒng)自動創(chuàng)建,子線程中RunLoop可以通過手動創(chuàng)建
RunLoop在線程結(jié)束的時候會被銷毀

1跛璧、獲取RunLoop對象Foundation框架中
[NSRunLoop currentRunLoop]; // 獲得當(dāng)前線程的RunLoop對象
[NSRunLoop mainRunLoop]; // 獲得主線程的RunLoop對象

2严里、Core Foundation框架中
CFRunLoopGetCurrent(); // 獲得當(dāng)前線程的RunLoop對象
CFRunLoopGetMain(); // 獲得主線程的RunLoop對象

3.注意點(diǎn):開一個子線程創(chuàng)建runloop,不是通過alloc init方法創(chuàng)建,而是直接通過調(diào)用currentRunLoop方法來創(chuàng)建追城,它本身是一個懶加載的刹碾。
4.在子線程中,如果不主動獲取Runloop的話座柱,那么子線程內(nèi)部是不會創(chuàng)建Runloop的迷帜∥锸妫可以下載CFRunloopRef的源碼,搜索_CFRunloopGet0,查看代碼戏锹。
5.Runloop對象是利用字典來進(jìn)行存儲冠胯,而且key是對應(yīng)的線程Value為該線程對應(yīng)的Runloop。
4锦针、RunLoop的結(jié)構(gòu)
RunLoop相關(guān)聯(lián)的類有五個
  • CFRunLoopRef
  • CFRunLoopSourceRef
  • CFRunLoopObserverRef
  • CFRunLoopTimerRef
  • CFRunLoopModeRef
runloop

RunLoop的結(jié)構(gòu)
5荠察、RunLoop相關(guān)類的理解

1.從上圖可以看出

  • 一個RunLoop 可以有多個Mode(模式),每個模式又包含若干個 Source/Observer/Timer
  • RunLoop 一次只能運(yùn)行一種Mode,切換Mode需要退出當(dāng)前Mode

2.CFRunLoopModeRef 一共有五種模式

  • kCFRunLoopDefaultMode 默認(rèn)模式奈搜,通常主線程在這個模式下運(yùn)行
  • kCFRunLoopCommonModes 占位符(表示)
  • UITrackingRunLoopMode 界面跟蹤Mode悉盆,用于追蹤Scrollview的觸摸滑動
  • UIInitializationRunLoopMode:剛啟動App時進(jìn)入的第一個Mode,啟動后不在使用馋吗。
  • GSEventReceiveRunLoop:內(nèi)部Mode焕盟,接收系事件。

3.CFRunLoopSourceRef(函數(shù)調(diào)用棧)

  • Source0:非基于Port(處理事件)
  • Source1:基于Port (接收分發(fā)系統(tǒng)事件)

4.CFRunLoopTimerRef:基于時間的觸發(fā)器(和NSTimer差不多)
5.CFRunLoopObserverRef:監(jiān)聽RunLoop狀態(tài)的觀察者

CFRunLoopObserverRef是RunLoop的觀察者耗美,可以通過CFRunLoopObserverRef來監(jiān)聽RunLoop狀態(tài)的改變

typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
      /* Run Loop Observer Activities */
      typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
          kCFRunLoopEntry = (1UL << 0),         // 狀態(tài)值:1,表示進(jìn)入RunLoop
          kCFRunLoopBeforeTimers = (1UL << 1),  // 狀態(tài)值:2,表示即將處理NSTimer
          kCFRunLoopBeforeSources = (1UL << 2), // 狀態(tài)值:4,表示即將處理Sources
          kCFRunLoopBeforeWaiting = (1UL << 5), // 狀態(tài)值:32,表示即將休眠
          kCFRunLoopAfterWaiting = (1UL << 6),  // 狀態(tài)值:64,表示從休眠中喚醒
          kCFRunLoopExit = (1UL << 7),          // 狀態(tài)值:128,表示退出RunLoop
          kCFRunLoopAllActivities = 0x0FFFFFFFU // 表示監(jiān)聽上面所有的狀態(tài)
      };
};
  • 如何監(jiān)聽RunLoop的狀態(tài):
  • 1.創(chuàng)建CFRunLoopObserverRef
// 第一個參數(shù)用于分配該observer對象的內(nèi)存
// 第二個參數(shù)用以設(shè)置該observer所要關(guān)注的的事件京髓,詳見回調(diào)函數(shù)myRunLoopObserver中注釋
// 第三個參數(shù)用于標(biāo)識該observer是在第一次進(jìn)入run loop時執(zhí)行還是每次進(jìn)入run loop處理時均執(zhí)行
// 第四個參數(shù)用于設(shè)置該observer的優(yōu)先級,一般為0
// 第五個參數(shù)用于設(shè)置該observer的回調(diào)函數(shù)
// 第六個參數(shù)observer的運(yùn)行狀態(tài)   
CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
      NSLog(@"----監(jiān)聽到RunLoop狀態(tài)發(fā)生改變---%zd", activity);
      });
  • 2.將觀察者CFRunLoopObserverRef添加到RunLoop上面
CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);
  • 3.觀察者CFRunLoopObserverRef要手動釋放
 CFRelease(observer);````

6航缀、RunLoop 處理邏輯

![RunLoop 處理邏輯](http://upload-images.jianshu.io/upload_images/785453-846c6532a9e0b7ba.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

#####6商架、RunLoop 使用
1.圖片刷新(假如界面要刷新N多圖片(渲染),此時用戶拖拽UI控件就會出現(xiàn)卡的效果芥玉,我們可以通過RunLoop實(shí)現(xiàn)蛇摸,只在RunLoop默認(rèn)Mode下下載,也就是拖拽Mode下不刷新圖片)
  • (void)viewDidLoad {
    [super viewDidLoad];
    // 只在NSDefaultRunLoopMode下執(zhí)行(刷新圖片)
    [self.myImageView performSelector:@selector(setImage:) withObject:[UIImage imageNamed:@"0"] afterDelay:2.0 inModes:@[NSDefaultRunLoopMode]];
    }

2.在RunLoop中創(chuàng)建定時器:
> - 1灿巧、第一種方式
  - 定時器NSTimer的創(chuàng)建方式一:timerWithTimeInterval:
 - 創(chuàng)建timer
 - 將timer 添加到RunLoop中
- 第二種方式
  NSTimer 和 scheduledTimerWithTimeInterval赶袄,這個不用加在runloop中,默認(rèn)Mode:NSDefaultRunLoopMode

objc
// 創(chuàng)建一個定時器
NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];
// NSDefaultRunLoopMode:NSTimer只有在默認(rèn)模式下(NSDefaultRunLoopMode)工作抠藕,切換到其他模式不再工作饿肺,比如拖拽了界面上的某個控件(會切換成UITrackingRunLoopMode)
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
objc
// 創(chuàng)建一個定時器
NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];
// 拖拽UI界面時出發(fā)定時器,在默認(rèn)模式(NSDefaultRunLoopMode)下不工作
[[NSRunLoop mainRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];
objc
// 創(chuàng)建一個定時器
NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];
// NSRunLoopCommonModes僅僅是標(biāo)記NSTimer在兩種模式(UITrackingRunLoopMode/NSDefaultRunLoopMode)下都能運(yùn)行,但一個RunLoop中同一時間內(nèi)只能運(yùn)行一種模式
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
objc
// 默認(rèn)已經(jīng)添加到主線程中RunLoop(mainRunLoop)中(Mode:NSDefaultRunLoopMode)
[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];


3.保證一個線程永遠(yuǎn)不死

import "ViewController.h"

/*
思路:為了保證線程不死,我們考慮在子線程中加入RunLoop盾似,
但是由于RunLoop中沒有沒有源敬辣,就會自動退出RunLoop,
所以我們要為子線程添加一個RunLoop零院,
并且為這個RunLoop添加源(保證RunLoop不退出)
*/
@interface ViewController ()

/** 線程對象 */
@property (nonatomic, strong)NSThread *thread;

@end

@implementation ViewController

  • (void)viewDidLoad {
    [super viewDidLoad];

    // 創(chuàng)建子線程
    self.thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];

    //啟動子線程
    [self.thread start];

}

  • (void)run {

    NSLog(@"run--%@", [NSThread currentThread]); // 子線程

    // 給子線程添加一個RunLoop溉跃,并且加入源
    [[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
    // 啟動RunLoop
    [[NSRunLoop currentRunLoop] run];
    NSLog(@"------------"); // RunLoop啟動,這句沒有執(zhí)行的機(jī)會
    }

  • (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    // 在子線程中調(diào)用test方法告抄,如果子線程還在就能夠調(diào)用成功
    [self performSelector:@selector(test) onThread:self.thread withObject:nil waitUntilDone:YES modes:@[NSDefaultRunLoopMode]];
    }

  • (void)test {
    NSLog(@"test--%@", [NSThread currentThread]); // 子線程
    }

@end

#####8撰茎、RunLoop的面試題
1.runloop與autoreleasepool的關(guān)系
>  
- 第一次創(chuàng)建:進(jìn)入runloop的時候
- 最后一次釋放:runloop退出的時候
- 其它創(chuàng)建和釋放:當(dāng)runloop即將休眠的時候會把之前的自動釋放池釋放,然后重新創(chuàng)建一個新的釋放池

2.如何處理滑動UI過程中打洼,廣告輪播圖停止輪詢問題龄糊,使用runloop的哪種模式
> 這個問題其實(shí)看在"RunLoop中創(chuàng)建定時器"就可以了
- kCFRunLoopDefaultMode

3.runloop有幾種模式逆粹,runloop接收幾種輸入源
> 
######  runloop有幾種模式
- kCFRunLoopDefaultMode 默認(rèn)模式,通常主線程在這個模式下運(yùn)行
- kCFRunLoopCommonModes 占位符(表示)
- UITrackingRunLoopMode 界面跟蹤Mode炫惩,用于追蹤Scrollview的觸摸滑動
- UIInitializationRunLoopMode:剛啟動App時進(jìn)入的第一個Mode枯饿,啟動后不在使用。
- GSEventReceiveRunLoop:內(nèi)部Mode诡必,接收系事件奢方。

> ######runloop接收幾種輸入源
 - Source0:非基于Port(處理事件)
 - Source1:基于Port (接收分發(fā)系統(tǒng)事件)

#####9、參考資料
[ CFRunLoopRef](http://opensource.apple.com/source/CF/CF-1151.16/)
[官方文檔](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Multithreading/RunLoopManagement/RunLoopManagement.html)
[sunnyxxx線下視頻](http://pan.baidu.com/s/1o8GRQ9W)
密碼: jwnp
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末爸舒,一起剝皮案震驚了整個濱河市蟋字,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌扭勉,老刑警劉巖鹊奖,帶你破解...
    沈念sama閱讀 216,997評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異涂炎,居然都是意外死亡忠聚,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評論 3 392
  • 文/潘曉璐 我一進(jìn)店門唱捣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來两蟀,“玉大人,你說我怎么就攤上這事震缭÷柑海” “怎么了?”我有些...
    開封第一講書人閱讀 163,359評論 0 353
  • 文/不壞的土叔 我叫張陵拣宰,是天一觀的道長党涕。 經(jīng)常有香客問我,道長巡社,這世上最難降的妖魔是什么膛堤? 我笑而不...
    開封第一講書人閱讀 58,309評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮晌该,結(jié)果婚禮上肥荔,老公的妹妹穿的比我還像新娘。我一直安慰自己气笙,他們只是感情好次企,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,346評論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著潜圃,像睡著了一般缸棵。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上谭期,一...
    開封第一講書人閱讀 51,258評論 1 300
  • 那天堵第,我揣著相機(jī)與錄音吧凉,去河邊找鬼。 笑死踏志,一個胖子當(dāng)著我的面吹牛阀捅,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播针余,決...
    沈念sama閱讀 40,122評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼饲鄙,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了圆雁?” 一聲冷哼從身側(cè)響起忍级,我...
    開封第一講書人閱讀 38,970評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎伪朽,沒想到半個月后轴咱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,403評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡烈涮,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,596評論 3 334
  • 正文 我和宋清朗相戀三年朴肺,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片坚洽。...
    茶點(diǎn)故事閱讀 39,769評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡戈稿,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出酪术,到底是詐尸還是另有隱情器瘪,我是刑警寧澤,帶...
    沈念sama閱讀 35,464評論 5 344
  • 正文 年R本政府宣布绘雁,位于F島的核電站,受9級特大地震影響援所,放射性物質(zhì)發(fā)生泄漏庐舟。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,075評論 3 327
  • 文/蒙蒙 一住拭、第九天 我趴在偏房一處隱蔽的房頂上張望挪略。 院中可真熱鬧,春花似錦滔岳、人聲如沸杠娱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽摊求。三九已至,卻和暖如春刘离,著一層夾襖步出監(jiān)牢的瞬間室叉,已是汗流浹背睹栖。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留茧痕,地道東北人野来。 一個月前我還...
    沈念sama閱讀 47,831評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像踪旷,于是被迫代替她去往敵國和親曼氛。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,678評論 2 354

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

  • 一令野、什么是runloop 字面意思是“消息循環(huán)搪锣、運(yùn)行循環(huán)”。它不是線程彩掐,但它和線程息息相關(guān)构舟。一般來講,一個線程一次...
    WeiHing閱讀 8,128評論 11 111
  • 轉(zhuǎn)載:http://www.cocoachina.com/ios/20150601/11970.html RunL...
    Gatling閱讀 1,438評論 0 13
  • http://www.cocoachina.com/ios/20150601/11970.html RunLoop...
    紫色冰雨閱讀 837評論 0 3
  • 原文地址:http://blog.ibireme.com/2015/05/18/runloop/ RunLoop ...
    大餅炒雞蛋閱讀 1,156評論 0 6
  • 2017年6月3號 日出東北 日落西北 天氣陰天 天上的烏云像大朵大朵的浪花 氣溫悶熱 數(shù)學(xué)課堂氛圍一般 數(shù)學(xué)老師...
    藍(lán)桉lu閱讀 171評論 0 0