iOS--NSRunLoop

什么是RunLoop

RunLoop即消息機(jī)制的處理模式躲胳。NSRunLoop的作用在于有事情做的時(shí)候使的當(dāng)前NSRunLoop的線程工作,沒有事情做讓當(dāng)前NSRunLoop的線程休眠首昔。

主要職責(zé):

1.保證程序的持續(xù)運(yùn)行并接受用戶的輸入叶组。

2.節(jié)省CPU時(shí)間,即有任務(wù)的時(shí)候就干活圆仔,沒任務(wù)的話就休息

3.去決定程序在什么時(shí)候去處理一些Event

4.調(diào)用解耦(Message Queue)

誰依賴NSRunloop

NSTimer

UIEvent

autorelease

NSObject(NSDelaydPerforming)

NSObject(NSThreadPerformAddtion)

CADisplayLink

CATransition

CAAnimation

dispatch_get_main_queue()

等垃瞧。


/*-------------啟動runLoop------------------*//*

?通過[NSRunLoop currentRunLoop]或者? CFRunLoopGetCurrent()方式可以獲取到當(dāng)前線程的runLoop。根據(jù)蘋果公司的文檔坪郭,啟動一個(gè)runLoop有以下三種方法:

?- (void)run;

?- (void)runUntilDate:(NSDate *)limitDate;?

- (BOOL)runMode:(NSRunLoopMode)mode beforeDate:(NSDate *)limitDate;

1.使用第一種方式runLoop會一直運(yùn)行下去个从,在此期間會處理來自輸入源的數(shù)據(jù),并且會在NSDefaultRunLoopMode模式下重復(fù)調(diào)用 - (BOOL)runMode:(NSRunLoopMode)mode beforeDate:(NSDate *)limitDate方法?

2.使用第二種啟動方式歪沃,可以設(shè)置超時(shí)時(shí)間嗦锐,在超時(shí)時(shí)間到達(dá)之前,runLoop會一直運(yùn)行沪曙,在此期間runLoop會處理來自輸入源的數(shù)據(jù)奕污,并且也會在NSDefaultRunLoopMode模式下重復(fù)調(diào)用 - (BOOL)runMode:(NSRunLoopMode)mode beforeDate:(NSDate *)limitDate;方法?

3.使用第三種方法runLoop會運(yùn)行一次,超時(shí)時(shí)間到達(dá)或者一個(gè)輸入源被處理液走,則runLoop就會自動退出 */? ?

?? ? /*-----------------退出runLoop---------------------*/

/* 這是較好退出方式 第三種啟動方式runMode:beforeDate: 通過這種方式啟動碳默,runloop會運(yùn)行一次,當(dāng)超時(shí)時(shí)間到達(dá)或者第一個(gè)輸入源被處理嘱根,runloop就會退出该抒。測試代碼如下:

?- (void)createRunLoopInNewThread {?

// 注冊runloop觀察者?

static CFRunLoopObserverRef _observer; RegisterRunLoopObserver(kCFRunLoopAllActivities, _observer, 0, kCFRunLoopDefaultMode, (__bridge void*)self, RunLoopCallBack);?

?_theRL = [NSRunLoop currentRunLoop];?

?_port = (NSMachPort *)[NSMachPort port]; [_theRL addPort:_port forMode:NSDefaultRunLoopMode];?

?[_theRL runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];? // 如果當(dāng)前線程的runloop沒有退出欧引,則`[_theRL run]`之后的代碼不會執(zhí)行. NSLog(@"runloop已退出"); //只有當(dāng)runloop退出,這里才會執(zhí)行瞬哼。可以通過注冊runloop觀察者進(jìn)行驗(yàn)證,這里就不貼代碼了,具體代碼請到demo里查看。 }??

#pragma mark - Touch?

?- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent *)event {?

UIColor *color = self.view.backgroundColor;?

self.view.backgroundColor = color == [UIColor redColor] ? [UIColor yellowColor] : [UIColor redColor];?

?// 線程間的通信 (這里是main thread) [self performSelector:@selector(communicateToNewThreadFromMainThread) onThread:_thread withObject:nil waitUntilDone:NO]; }?

?- (void)communicateToNewThreadFromMainThread { NSLog(@"communicate successfully "); //這里是com.xindong.thread. 這里執(zhí)行完排惨,表示第一個(gè)輸入源事件被處理. } 當(dāng)我們觸摸屏幕時(shí),communicateToNewThreadFromMainThread方法被執(zhí)行匾效,即輸入源事件被處理,然后runloop退出。如果我們想控制runloop的退出時(shí)機(jī)虎敦,而不是在處理完一個(gè)輸入源事件之后就退出,那么就要重復(fù)調(diào)用runMode:beforeDate:政敢,

具體可以參考蘋果文檔給出的方案其徙,如下:

?BOOL shouldKeepRunning = YES;

?// global NSRunLoop *theRL = [NSRunLoop currentRunLoop];

?while (shouldKeepRunning && [theRL runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);?

接著我們對代碼進(jìn)行修改,以便我們可以控制runloop的退出時(shí)機(jī)喷户,改后如下:

?- (void)createRunLoopInNewThread {

?// 注冊runloop觀察者 static CFRunLoopObserverRef _observer; RegisterRunLoopObserver(kCFRunLoopAllActivities, _observer, 0, kCFRunLoopDefaultMode, (__bridge void*)self, RunLoopCallBack);?

?_theRL = [NSRunLoop currentRunLoop];?

?_port = (NSMachPort *)[NSMachPort port]; [_theRL addPort:_port forMode:NSDefaultRunLoopMode];??

while (shouldKeepRunning && [_theRL runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);? // 如果當(dāng)前線程的runloop沒有退出唾那,則`[_theRL run]`之后的代碼不會執(zhí)行. NSLog(@"runloop已退出"); //只有當(dāng)runloop退出,這里才會執(zhí)行褪尝∧只瘢可以通過注冊runloop觀察者進(jìn)行驗(yàn)證,這里就不貼代碼了河哑,具體代碼請到demo里查看避诽。 }??

#pragma mark - Touch? - (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent *)event {

UIColor *color = self.view.backgroundColor;

self.view.backgroundColor = color == [UIColor redColor] ? [UIColor yellowColor] : [UIColor redColor];

// 線程間的通信 (這里是main thread)

[self performSelector:@selector(communicateToNewThreadFromMainThread) onThread:_thread withObject:nil waitUntilDone:NO];

}

- (void)communicateToNewThreadFromMainThread {

NSLog(@"communicate successfully "); //這里是com.xindong.thread

[self quitRunLoop];

}

- (void)quitRunLoop {

shouldKeepRunning = NO;

CFRunLoopStop(CFRunLoopGetCurrent());

}

通過上述方式啟動和退出runloop,沒有引起內(nèi)存泄漏璃谨,也沒有造成內(nèi)存增長茎用,并且對runloop的退出時(shí)機(jī)可以自由控制。相對來說睬罗,使用此方案更好一些轨功。

*/

/*

注意

RunLoop在同一段時(shí)間只能且必須在一種特定Mode下Run。

更換Mode時(shí)容达,需要停止當(dāng)前Loop古涧,然后重啟新Mode。

Mode是iOS滑動順暢的關(guān)鍵花盐。

Mode中有三個(gè)非常重要的組成部分羡滑,Timer(定時(shí)器)、 Source(事件源) 以及Observor(觀察者)算芯。一個(gè) RunLoop 包含若干個(gè) Mode柒昏,每個(gè) Mode 又包含若干個(gè) Source/Timer/Observer。首先要指出的是一個(gè)runloop啟動時(shí)必須指定一個(gè)Mode? , 并且這個(gè)Mode被稱為currentMode 熙揍。如果要切換Mode,只能退出runloop重新進(jìn)入职祷。這樣做主要是為了分隔開不同組的 Source/Timer/Observer,讓其互不影響。

類型

NSDefaultRunLoopMode

默認(rèn)狀態(tài)(空閑狀態(tài))有梆,比如點(diǎn)擊按鈕都是這個(gè)狀態(tài)

UITrackingRunLoopMode

滑動時(shí)的Mode是尖。比如滑動UIScrollView時(shí)。

UIInitializationRunLoopMode

私有的泥耀,APP啟動時(shí)饺汹。就是從iphone桌面點(diǎn)擊APP的圖標(biāo)進(jìn)入APP到第一個(gè)界面展示之前,在第一個(gè)界面顯示出來后痰催,UIInitializationRunLoopMode就被切換成了NSDefaultRunLoopMode兜辞。

NSRunLoopCommonModes

它是NSDefaultRunLoopMode和UITrackingRunLoopMode的集合。結(jié)構(gòu)類似于一個(gè)數(shù)組夸溶。在這個(gè)mode下執(zhí)行其實(shí)就是兩個(gè)mode都能執(zhí)行而已弦疮。

典型的應(yīng)用場景這樣:當(dāng)前界面有開啟一個(gè)NSTimer,并且滑動UIScrollView蜘醋。正常開啟NSTimer后胁塞,滑動UIScrollView時(shí)它是不滑動的。解決辦法就是把這個(gè)timer加入到當(dāng)前的RunLoop压语,并把RunLoop的mode設(shè)置為NSRunLoopCommonModes啸罢。這樣就可以保證不管你是NSDefaultRunLoopMode里跑,還是UITrackingRunLoopMode里跑胎食,這個(gè)timer都可以執(zhí)行扰才。

RunLoop和GCD的關(guān)系

RunLoop和GCD的關(guān)系,準(zhǔn)確來說是只要使用了dispatch_get_main_queue()厕怜,就與RunLoop有了關(guān)系衩匣。

NSRunloop與程序運(yùn)行

程序的入口——main.m文件,一個(gè)ios程序啟動后粥航,只有短短的十行代碼居然能保持整個(gè)應(yīng)用程序一直運(yùn)行而沒有退出琅捏,是不是有點(diǎn)意思?程序之所以沒有直接退出是因?yàn)閁IApplicationMain這個(gè)函數(shù)內(nèi)部默認(rèn)啟動了一個(gè)跟主線程相關(guān)的NSRunloop對象递雀,而UIApplicationMain這個(gè)函數(shù)一直執(zhí)行沒有返回就保存程序一直運(yùn)行的狀態(tài)柄延。


-------------總結(jié)-----------------

如果不想退出runLoop可以使用第一種啟動方法;如果使用第二種方式啟動runLoop缀程,可以通過設(shè)置超時(shí)時(shí)間來退出搜吧;如果使用第三種方式啟動runLoop,可以通過設(shè)置超時(shí)時(shí)間或者使用CFRunLoopStop方法來退出

*/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末杨凑,一起剝皮案震驚了整個(gè)濱河市滤奈,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌撩满,老刑警劉巖蜒程,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件绅你,死亡現(xiàn)場離奇詭異,居然都是意外死亡搞糕,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進(jìn)店門曼追,熙熙樓的掌柜王于貴愁眉苦臉地迎上來窍仰,“玉大人,你說我怎么就攤上這事礼殊【运保” “怎么了?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵晶伦,是天一觀的道長碟狞。 經(jīng)常有香客問我,道長婚陪,這世上最難降的妖魔是什么族沃? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮泌参,結(jié)果婚禮上脆淹,老公的妹妹穿的比我還像新娘。我一直安慰自己沽一,他們只是感情好盖溺,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著铣缠,像睡著了一般烘嘱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蝗蛙,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天蝇庭,我揣著相機(jī)與錄音,去河邊找鬼捡硅。 笑死遗契,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的病曾。 我是一名探鬼主播牍蜂,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼泰涂!你這毒婦竟也來了鲫竞?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤逼蒙,失蹤者是張志新(化名)和其女友劉穎从绘,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡僵井,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年陕截,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片批什。...
    茶點(diǎn)故事閱讀 39,965評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡农曲,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出驻债,到底是詐尸還是另有隱情乳规,我是刑警寧澤,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布合呐,位于F島的核電站暮的,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏淌实。R本人自食惡果不足惜冻辩,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望拆祈。 院中可真熱鬧微猖,春花似錦、人聲如沸缘屹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽轻姿。三九已至犁珠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間互亮,已是汗流浹背犁享。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留豹休,地道東北人炊昆。 一個(gè)月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像威根,于是被迫代替她去往敵國和親凤巨。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評論 2 355

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

  • 一洛搀、什么是runloop 字面意思是“消息循環(huán)敢茁、運(yùn)行循環(huán)”。它不是線程留美,但它和線程息息相關(guān)彰檬。一般來講伸刃,一個(gè)線程一次...
    WeiHing閱讀 8,136評論 11 111
  • 2017-08-05iOS開發(fā) 1.啟動RunLoop 通過[NSRunLoop currentRunLoop]或...
    C9090閱讀 1,245評論 0 0
  • ======================= 前言 RunLoop 是 iOS 和 OSX 開發(fā)中非常基礎(chǔ)的一個(gè)...
    i憬銘閱讀 879評論 0 4
  • 基本概念 進(jìn)程 進(jìn)程是指在系統(tǒng)中正在運(yùn)行的一個(gè)應(yīng)用程序逢倍,而且每個(gè)進(jìn)程之間是獨(dú)立的捧颅,它們都運(yùn)行在其專用且受保護(hù)的內(nèi)存...
    小楓123閱讀 893評論 0 1
  • 曾幾何時(shí)碉哑,許多人暢想著每天只上一上午課,睡覺睡到自然醒郎笆,充裕的時(shí)間出去游玩的大學(xué)生活谭梗。也有一部分人認(rèn)為每天...
    烽火煙雨閱讀 270評論 0 0