今天整理一下運(yùn)行循環(huán)來幫朋友們了解一下什么是運(yùn)行循環(huán),也叫消息循環(huán),建議大家稱之為運(yùn)行循環(huán)(Runloop).
===
關(guān)于多線程的運(yùn)行循環(huán)(消息循環(huán))
1. 什么是運(yùn)行循環(huán)
(1)Runloop就是運(yùn)行循環(huán),每個線程內(nèi)部都有一個運(yùn)行循環(huán).
(2)只有主線程的運(yùn)行循環(huán)默認(rèn)是開啟的,子線程的運(yùn)行循環(huán).
2. 運(yùn)行循環(huán)的作用
(1)保證程序不退出,iOS的應(yīng)用程序啟動之后,之所以不會退出,就是因為有Runloop(運(yùn)行循環(huán)).運(yùn)行循環(huán)是一個死循環(huán),只有滿足一定條件才會結(jié)束循環(huán).
(2)負(fù)責(zé)處理輸入事件
(3)如果沒有事件發(fā)生,會讓程序進(jìn)入休眠狀態(tài).
3.輸入事件
Runloop接收的事件來自兩種不同的來源:輸入源 和 定時源.
(1)輸入源(Input sources)輸入源傳遞異步事件,通常消息來自于其他線程或程序坷剧。
(2)定時源(Timer sounces)定時源則傳遞同步事件陵叽,發(fā)生在特定時間或者重復(fù)的時間間隔独令。兩種源都使用程序的某一特定的處理例程來處理到達(dá)的事件。
(3)下圖展示了運(yùn)行循環(huán)的概念結(jié)構(gòu)以及事件來源的種類:
輸入源能夠通過runUntilDate 方法使線程退出;定時源不能使線程退出.
4.運(yùn)行循環(huán)的模式
運(yùn)行循環(huán)模式是輸入源和定時源的一個集合,這個集合會被監(jiān)聽.
每次啟動運(yùn)行循環(huán)稠曼,可以指定一個特殊的模式,在運(yùn)行循環(huán)執(zhí)行期間客年,只有跟特定的模式相關(guān)聯(lián)的事件源才會被監(jiān)聽以及允許傳遞它們的事件霞幅。跟其它模式相關(guān)聯(lián)的事件源將不會被監(jiān)聽。因此量瓜,可以通過運(yùn)行循環(huán)來過濾掉一些不期望的事件
下圖是系統(tǒng)定義的幾種運(yùn)行循環(huán)模式:
Mode | Name | Description |
---|---|---|
Default | NSDefaultRunLoopMode(Cocoa)kCFRunLoopDefaultMode (Core Foundation) | The default mode is the one used for most operations. Most of the time, you should use this mode to start your run loop and configure your input sources. |
Connection | NSConnectionReplyMode(Cocoa) | Cocoa uses this mode in conjunction with NSConnection objects to monitor replies. You should rarely need to use this mode yourself |
Modal | NSModalPanelRunLoopMode(Cocoa) | Cocoa uses this mode to identify events intended for modal panels. |
Event tracking | NSEventTrackingRunLoopMode(Cocoa) | Cocoa uses this mode to restrict incoming events during mouse-dragging loops and other sorts of user interface tracking loops. |
Common modes | NSRunLoopCommonModes(Cocoa)kCFRunLoopCommonModes (Core Foundation) | This is a configurable group of commonly used modes. Associating an input source with this mode also associates it with each of the modes in the group. For Cocoa applications, this set includes the default, modal, and event tracking modes by default. Core Foundation includes just the default mode initially. You can add custom modes to the set using theCFRunLoopAddCommonMode function. |
大致的意思是指:
(1)Default: default模式可以用于大多數(shù)操作司恳。在大多數(shù)時間,應(yīng)該使用這種模式來啟動和設(shè)置輸入源绍傲。
(2)Connection: Cocoa使用這種模式聯(lián)合NSConnection對象來監(jiān)聽響應(yīng)扔傅。我們很少會自己用到這種模式
(3)Modal: Cocoa使用這種模式來識別為模態(tài)面板準(zhǔn)備的事件。
(4)Event tracking: Cocoa使用這種模式來約束鼠標(biāo)拖拽或其它用戶界面追蹤循環(huán)的事件烫饼。
(5)Common modes: 這是一個通用的模式組猎塞,使用這種模式關(guān)聯(lián)輸入源,同樣會關(guān)聯(lián)這個模式組里面的每一種模式枫弟。對于Cocoa應(yīng)用來說邢享,這個集合包含了 default、modal以及event tracking模式淡诗。
Core Foundation初始狀態(tài)下只包含 default 模式骇塘,但是可以
通過 CFRunLoopAddCommonMode函數(shù)來添加自定義模式。
5.通過定時器演示運(yùn)行循環(huán)的模式
注意:定時器執(zhí)行的方法中不宜執(zhí)行太耗時的操作,否則會降低用戶體驗.
- 第一步:創(chuàng)建定時器
在viewDidLoad方法中:
//1,創(chuàng)建定時器
NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:
self selector:@selector(demo) userInfo:nil repeats:YES];
//demo方法
- (void)demo {
NSLog(@"hello");
}
- 第二步:將定時器添加到當(dāng)前線程的運(yùn)行循環(huán)
//將定時器添加到當(dāng)前線程的運(yùn)行循環(huán)
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
===
注意:這里的模式對應(yīng)的是輸入事件(定時器timer)的模式.
- 第三步:運(yùn)行程序,執(zhí)行結(jié)果如下:
當(dāng)程序運(yùn)行起來之后,打印輸出會按照定時器,每秒輸出一次.但是,如果拖動界面的控件,打印輸出就會停止(即不再打印輸出).
思考:為什么?
- 第四步: 打印當(dāng)前運(yùn)行循環(huán)的模式
demo方法中:
NSLog(@"---%@", [NSRunLoop currentRunLoop].currentMode);
執(zhí)行程序:
注意:[NSRunLoop currentRunLoop].currentMode 中的模式對應(yīng)的是運(yùn)行循環(huán)的模式韩容。
結(jié)論:
運(yùn)行循環(huán)是在一個指定的模式下運(yùn)行的(默認(rèn)是NSDefaultRunLoopMode)款违,設(shè)置的輸入事件也需要指定一個模式,運(yùn)行循環(huán)的模式必須和輸入事件的模式相匹配才會執(zhí)行群凶。
一開始插爹,輸入事件模式是NSDefaultRunLoopMode,運(yùn)行循環(huán)默認(rèn)也是NSDefaultRunLoopMode螟深,所以可以正常輸出結(jié)果矮燎。
拖動控件,之所以不會打印輸出局义,就是因為運(yùn)行循環(huán)的模式發(fā)生了改變气嫁,變成了 UITrackingRunLoopMode当窗,這個時候二者模式不匹配,所以不能正常輸出寸宵。
總結(jié):
(1)運(yùn)行循環(huán)是在一個指定的模式下運(yùn)行的崖面,輸入事件也有對應(yīng)的模式,只有當(dāng)二者的模式相匹配梯影,對應(yīng)的方法才會執(zhí)行巫员。
(2)運(yùn)行循環(huán)模式:
1> 運(yùn)行循環(huán)啟動后,默認(rèn)模式為 NSRunLoopDefaultMode
2> 如果滾動scrollView甲棍,運(yùn)行循環(huán)模式為 UITrackingRunLoopMode简识。
子線程的運(yùn)行循環(huán)
主線程的運(yùn)行循環(huán)默認(rèn)是開啟的,子線程的運(yùn)行循環(huán)默認(rèn)是不開啟的救军。
//第一步: 創(chuàng)建子線程
viewDidLoad方法中:
// 創(chuàng)建子線程
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(demo) object:nil];
[thread start];
//第二步: 往子線程的運(yùn)行循環(huán)添加輸入源
// 往子線程的運(yùn)行循環(huán)上添加輸入源
[self performSelector:@selector(demo1) onThread:thread withObject:
nil waitUntilDone:NO];
// 執(zhí)行在子線程的方法
- (void)demo {
NSLog(@"I'm running");
}
// 執(zhí)行在子線程的運(yùn)行循環(huán)中的方法
- (void)demo1 {
- NSLog(@"I'm running on runloop");
}
第三步: 開啟子線程的運(yùn)行循環(huán)
- (void)demo {
NSLog(@"I'm running");
// 這些數(shù)入源能夠防止運(yùn)行循環(huán)退出, 即 只要有數(shù)入源, run 方法啟動的運(yùn)行循環(huán)就不會退出
// Those sources could therefore prevent the run loop from exiting.
[[NSRunLoop currentRunLoop] run];
NSLog(@"end");
}
然后執(zhí)行程序得到以下結(jié)果:
屏幕快照 2016-03-12 下午10.05.45.png
由輸出結(jié)果可知: 沒有打印 end财异,即只要有輸入源倘零,使用run方法啟動的運(yùn)行循環(huán)不會退出唱遭。
第五步: 通過 runUntilDate來啟動運(yùn)行循環(huán)
// 2秒鐘之后消息循環(huán)結(jié)束
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:2]];
這樣的話,2秒鐘之后呈驶,子線程的運(yùn)行循環(huán)就會退出拷泽。
希望能幫到大家!