一、RunLoop和線程的關(guān)系
? ? ? ?每條線程都有唯一的一個(gè)與之對(duì)應(yīng)的RunLoop對(duì)象,一個(gè)線程可以開(kāi)啟多個(gè)RunLoop,只不過(guò)都是嵌套在最大的RunLoop中证薇,其關(guān)系是保存在一個(gè)全局的 Dictionary 里桥氏。
二、線程中RunLoop的生命周期
創(chuàng)建:
? ? ?1瓣蛀、主線程:run loop默認(rèn)是啟動(dòng)的陆蟆,用于接收各種輸入sources
? ? ? 2、子線程:線程剛創(chuàng)建時(shí)并沒(méi)有 RunLoop惋增,如果你不主動(dòng)獲取叠殷,那它一直都不會(huì)有。
? ? ?在當(dāng)前子線程中調(diào)用[NSRunLoop currentRunLoop]的時(shí)候诈皿,如果有就獲取林束,沒(méi)有就創(chuàng)建
啟動(dòng):
? ? ?1、主線程:默認(rèn)是啟動(dòng)的
? ? ?2稽亏、子線程:要手動(dòng)添加
獲群啊:
? ? ?1、主線程:全局獲取其RunLoop;[NSRunLoop mainRunLoop]或者 CFRunLoopGetMain();
? ? ? 2截歉、子線程:只能在線程的內(nèi)部獲取其RunLoop;[NSRunLoop currentRunLoop]或者CFRunLoopGetCurrent();
銷毀:
? ? 1胖腾、主線程:app結(jié)束時(shí)
? ? 2、子線程:子線程結(jié)束
三、在當(dāng)前線程的Run Loop下執(zhí)行指定的 @selector 方法
? ? ?當(dāng)調(diào)用 NSObject的performSelector:onThread:時(shí)胸嘁,實(shí)際上其內(nèi)部會(huì)創(chuàng)建一個(gè) Timer 并添加到當(dāng)前線程的 RunLoop 中:
打印一下看看:
看以下的代碼:
- (void)viewDidLoad {
? ? ?[super viewDidLoad];
? ? ?NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(nslogHi) object:nil];
? ? ?[thread start];
? ? ?[self performSelector:@selector(nslogHello) onThread:thread withObject:nil waitUntilDone:NO];
? ? NSLog(@"_end");
}
- (void)nslogHi {
? ? ? NSLog(@"hi....");
}
- (void)nslogHello {
? ? ? NSLog(@"hello.....");
}
最會(huì)輸出:
? ? ?2015-09-28 14:09:15.650 PCRunLoopThread[74414:5556013] hi....
? ? ?2015-09-28 14:09:15.650 PCRunLoopThread[74414:5555961] _end
結(jié)論:
? ? ? 1瓶摆、線程在執(zhí)行后會(huì)退出當(dāng)前的RunLoop,也就是RunLoop會(huì)在一個(gè)線程結(jié)束時(shí)一同銷毀性宏。
? ? ? 2群井、如果當(dāng)前線程沒(méi)有RunLoop的話,performSelector:onThread的方法也就失效毫胜。
==================================================
那么我們要想要把hello.....打印出來(lái)J樾薄!要怎么辦呢酵使?
就線程一直運(yùn)行或者暫時(shí)阻塞一下線程:
1荐吉、向創(chuàng)建的RunLoop添加NSPort(Sources),讓Mode不為空口渔,RunLoop能進(jìn)入循環(huán)不會(huì)退出
? ? ? [[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
? ? ? [[NSRunLoop currentRunLoop] run];
見(jiàn)代碼:
- (void)nslogHi {
? ? ? [[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
? ? ? [[NSRunLoop currentRunLoop] run];
? ? ?NSLog(@"hi....");
}
使用run啟動(dòng)線程样屠,是不會(huì)退出,所以也就打印不出hi....
2缺脉、讓RunLoop一直嘗試運(yùn)行痪欲,判斷Mode是否為空,不是為空就進(jìn)入RunLoop循環(huán)
? ? ? ?[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]
見(jiàn)代碼:
- (void)nslogHi {
? ? ?while (!_isNewThreadAborted) {
? ? ? ? ? ? ?BOOL ret = [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
? ? ? ? ? ? beforeDate:[NSDate distantFuture]];
? ? ? ? }
? ? ? ? NSLog(@"hi....");
}
網(wǎng)上找了些資料攻礼,貼一下的三種手動(dòng)啟動(dòng)runloop的方式:
讓一個(gè)子線程不進(jìn)入消亡狀態(tài)业踢,等待其他線程發(fā)來(lái)消息,處理其他事件,其實(shí)就是讓線程跑一個(gè)runLoop
1礁扮、- (void)run;
運(yùn)行 NSRunLoop知举,運(yùn)行模式為默認(rèn)的NSDefaultRunLoopMode模式,沒(méi)有超時(shí)限制太伊。因?yàn)闊o(wú)條件運(yùn)行
不建議使用雇锡,因?yàn)檫@個(gè)接口會(huì)導(dǎo)致Run Loop永久性的運(yùn)行在NSDefaultRunLoopMode模式,即使使用CFRunLoopStop(runloopRef);也無(wú)法停止Run Loop的運(yùn)行僚焦,那么這個(gè)子線程就無(wú)法停止遮糖,只能永久運(yùn)行下去。
示例:
[[NSRunLoop currentRunLoop] run];
2叠赐、[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:10]];
運(yùn)行 NSRunLoop: 參數(shù)為運(yùn)時(shí)間期限,運(yùn)行模式為默認(rèn)的NSDefaultRunLoopMode模式屡江,自己設(shè)置的Run Loop運(yùn)行時(shí)間芭概,超時(shí)就退出
示例:
while (!Done)
{
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate
dateWithTimeIntervalSinceNow:10]];
NSLog(@"exiting runloop.........:");
}
3、- (BOOL)runMode:(NSString *)mode beforeDate:(NSDate *)limitDate;
mode: ? 指定runloop模式來(lái)處理輸入源
limitDate:設(shè)置為NSDate distantFuture惩嘉,所以除非處理其他輸入源結(jié)束罢洲,否則永不退出處理暫停的當(dāng)前處理的流程
return: ? 返回值為YES表示是處理事件后返回的,NO表示是超時(shí)或者停止運(yùn)行導(dǎo)致返回的
這個(gè)接口在非Timer事件觸發(fā)、顯式的用CFRunLoopStop停止Run Loop惹苗、到達(dá)limitDate后會(huì)退出返回殿较。
如果僅是Timer事件觸發(fā)并不會(huì)讓Run Loop退出返回;
如果是PerfromSelector***事件或者其他Input Source事件觸發(fā)處理后桩蓉,Run Loop會(huì)退出返回YES淋纲。
示例:
while (!Done)
{
BOOL ret = [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
beforeDate:[NSDate distantFuture]];
NSLog(@"exiting runloop.........: %d", ret);
}
當(dāng)判斷條件為YES時(shí),當(dāng)前runloop會(huì)一直接收處理其他輸入源院究,當(dāng)前流程不繼續(xù)往下執(zhí)行洽瞬。
當(dāng)判斷出為A為NO,當(dāng)前流程繼續(xù)往下執(zhí)行