-
首先看兩個runloop的事例。
第一個:
#include <CoreFoundation/CoreFoundation.h> static void _perform(void *info __unused) { printf("hello\n"); } static void _timer(CFRunLoopTimerRef timer __unused, void *info) { CFRunLoopSourceSignal(info); } int main() { CFRunLoopSourceRef source; CFRunLoopSourceContext source_context; CFRunLoopTimerRef timer; CFRunLoopTimerContext timer_context; bzero(&source_context, sizeof(source_context)); source_context.perform = _perform; source = CFRunLoopSourceCreate(NULL, 0, &source_context); CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopCommonModes); bzero(&timer_context, sizeof(timer_context)); timer_context.info = source; timer = CFRunLoopTimerCreate(NULL, CFAbsoluteTimeGetCurrent(), 1, 0, 0, _timer, &timer_context); CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopCommonModes); CFRunLoopRun(); return 0; }
第二個:
#include <dispatch/dispatch.h> #include <stdio.h> int main() { dispatch_source_t source, timer; source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)); dispatch_source_set_event_handler(source, ^{ printf("hello\n"); }); dispatch_resume(source); timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)); dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1ull * NSEC_PER_SEC, 0); dispatch_source_set_event_handler(timer, ^{ dispatch_source_merge_data(source, 1); }); dispatch_resume(timer); dispatch_main(); }
功能是向main線程中加入兩個input source,一個是timer,一個是自定義input source,然後這個timer中觸發自定義source,於是調用其回調方法。 在這兒timer觸發source來調用回調方法,顯得有點多此一舉。但是在多線程開發當中,這就很有用了,我們可以把這個自定義的source加入到子線程的runloop中,然後在主線程中觸發source,這樣在子線程中就可以調用回調方法了。 這樣做的好久是什麼呀? 節約用電,因爲runloop一般情況下是休眠的,只有事件觸發的時候纔開始工作。 這與windows下的waitforsingleobject有點類似, 與多線程中的信號量,事件也有些雷同。
上面說到的input source(輸入源例)到底是什麼呢?輸入源樣例可能包括用戶輸入設備(如點擊button)、網絡鏈接(socket收到數據)、定期或時間延遲事件(NSTimer),還有異步回調(NSURLConnection的異步請求)。然後我們對其進行了分類,有三類可以被runloop監控,分別是sources、timers、observers。
在蘋果文檔中對runloop有詳細介紹,下面參考中有中文版。那文檔中的代碼關於NSPort的部份在iOS上是不行的,不過可以用其CF方法實現,在我的demo中有展示。
每一個線程都有自己的runloop, 主線程是默認開啓的,創建的子線程要手動開啓,因爲NSApplication 只啓動main applicaiton thread。
沒有source的runloop會自動結束。
事件由NSRunLoop 類處理。
RunLoop監視操作系統的輸入源,如果沒有事件數據, 不消耗任何CPU 資源。
如果有事件數據,run loop 就發送消息,通知各個對象。
用 currentRunLoop 獲得 runloop的 reference
給 runloop 發送run 消息啓動它。
文檔中介紹下面四種情況是使用runloop的場合:
1.使用端口或自定義輸入源和其他線程通信
2.子線程中使用了定時器
3.cocoa中使用任何performSelector到了線程中運行方法
4.使線程履行週期性任務,(我把這個理解與2相同)
如果我們在子線程中用了NSURLConnection異步請求,那也需要用到runloop,不然線程退出了,相應的delegate方法就不能觸發。
解決的方法參看:
http://www.cocoabyss.com/foundation/nsurlconnection-synchronous-asynchronous/
http://www.wim.me/nsurlconnection-in-its-own-thread/
參考:
http://www.wim.me/nsurlconnection-in-its-own-thread/
http://iphonedevelopmentbits.com/event-driven-multitasking-runloopssymbian-ios
runloop
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.