如果你在非main thread中運行run loop,你必須至少為該run loop添加一個input sources或timer。如果你啟動並執行run loop沒有監控任何的輸入源,該run loop將在你運行後立即退出。
Run loop observer
使用detachNewThreadSelector:toTarget:withObject:建立一個thread:
[NSThread detachNewThreadSelector:@selector(observerRunLoop) toTarget:self withObject:nil];
在新thread的run loop中添加observer:
- (void)observerRunLoop { //建立自動釋放池 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; //獲得當前thread的Run loop NSRunLoop *myRunLoop = [NSRunLoop currentRunLoop]; //設定Run loop observer的運行環境 CFRunLoopObserverContext context = {0, self, NULL, NULL, NULL}; //建立Run loop observer對象 //第一個參數用於分配observer對象的記憶體 //第二個參數用以設定observer所要關注的事件,詳見回呼函數myRunLoopObserver中注釋 //第三個參數用於標識該observer是在第一次進入run loop時執行還是每次進入run loop處理時均執行 //第四個參數用於設定該observer的優先順序 //第五個參數用於設定該observer的回呼函數 //第六個參數用於設定該observer的運行環境 CFRunLoopObserverRef observer = CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopAllActivities, YES, 0, &myRunLoopObserver, &context); if (observer) { //將Cocoa的NSRunLoop類型轉換成Core Foundation的CFRunLoopRef類型 CFRunLoopRef cfRunLoop = [myRunLoop getCFRunLoop]; //將建立的observer加入到當前thread的run loop CFRunLoopAddObserver(cfRunLoop, observer, kCFRunLoopDefaultMode); } //Creates and returns a new NSTimer object and schedules it on the current run loop in the default mode [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(doFireTimer:) userInfo:nil repeats:YES]; NSInteger loopCount = 10; do { //啟動當前thread的loop直到所指定的時間到達,在loop運行時,run loop會處理所有來自與該run loop聯絡的input source的資料 //對於本例與當前run loop聯絡的input source只有一個Timer類型的source。 //該Timer每隔0.1秒發送觸發事件給run loop,run loop檢測到該事件時會調用相應的處理方法。 //由於在run loop添加了observer且設定observer對所有的run loop行為都感興趣。 //當調用runUnitDate方法時,observer檢測到run loop啟動並進入迴圈,observer會調用其回呼函數,第二個參數所傳遞的行為是kCFRunLoopEntry。 //observer檢測到run loop的其它行為並調用回呼函數的操作與上面的描述相類似。 [myRunLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]]; //當run loop的已耗用時間到達時,會退出當前的run loop。observer同樣會檢測到run loop的退出行為並調用其回呼函數,第二個參數所傳遞的行為是kCFRunLoopExit。 loopCount--; } while (loopCount); //釋放自動釋放池 [pool release];}
設定observer的回呼函數:
void myRunLoopObserver(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info) { switch (activity) { //The entrance of the run loop, before entering the event processing loop. //This activity occurs once for each call to CFRunLoopRun and CFRunLoopRunInMode case kCFRunLoopEntry: NSLog(@"run loop entry"); break; //Inside the event processing loop before any timers are processed case kCFRunLoopBeforeTimers: NSLog(@"run loop before timers"); break; //Inside the event processing loop before any sources are processed case kCFRunLoopBeforeSources: NSLog(@"run loop before sources"); break; //Inside the event processing loop before the run loop sleeps, waiting for a source or timer to fire. //This activity does not occur if CFRunLoopRunInMode is called with a timeout of 0 seconds. //It also does not occur in a particular iteration of the event processing loop if a version 0 source fires case kCFRunLoopBeforeWaiting: NSLog(@"run loop before waiting"); break; //Inside the event processing loop after the run loop wakes up, but before processing the event that woke it up. //This activity occurs only if the run loop did in fact go to sleep during the current loop case kCFRunLoopAfterWaiting: NSLog(@"run loop after waiting"); break; //The exit of the run loop, after exiting the event processing loop. //This activity occurs once for each call to CFRunLoopRun and CFRunLoopRunInMode case kCFRunLoopExit: NSLog(@"run loop exit"); break; /* A combination of all the preceding stages case kCFRunLoopAllActivities: break; */ default: break; }}
啟動run loop
啟動run loop的方法:無條件啟動,設定時間限制啟動,在特殊的模式下啟動。
以無條件模式進入run loop是最簡單的選擇,但並不是最好的選擇。以無條件的形式運行run loop將使thread進入一個永久的迴圈,這樣的操作會使使用者很難對run loop進行控制。你可以為該run loop添加input source或timer,但能退出該run loop的方法就是kill。這種啟動情況下並不能讓run loop運行於自訂模式中。
不同於無條件方式運行run loop,使用時間限制的方式啟動run loop更好。當你使用逾時時間來對run loop的運行加以限制,則run loop一直運行直至事件到達或達到逾時時間。如果是事件到達,run loop將事件分發給handler(處理器)進行處理並在處理完成後退出。你的代碼然後重啟run loop來處理下一個事件。如果是因到達逾時時間而退出,you can simply restart
the run loop or use the time to do any needed housekeeping。
除了逾時時間,你還可以運行run loop在特定的模式下。模式和逾時時間並不互斥,你可以在啟動一個run loop時同時指定逾時時間和模式。模式限制了投遞事件給run loop的sources的類型,詳細的見“iphone——NSRunLoop概念”。
退出run loop
退出run loop的方法:以逾時時間配置run loop啟動,顯式的停止run loop(調用CFRunLoopStop函數)。