RunLoop iOS運行迴路

from:http://www.cocoachina.com/iphonedev/sdk/2011/1111/3487.html

第一個:

  1. #include <CoreFoundation/CoreFoundation.h>  
  2.   
  3. static void  
  4. _perform(void *info __unused)  
  5. {  
  6.     printf("hello\n");  
  7. }  
  8.   
  9. static void  
  10. _timer(CFRunLoopTimerRef timer __unused, void *info)  
  11. {  
  12.     CFRunLoopSourceSignal(info);  
  13. }  
  14.   
  15. int  
  16. main()  
  17. {  
  18.     CFRunLoopSourceRef source;  
  19.     CFRunLoopSourceContext source_context;  
  20.     CFRunLoopTimerRef timer;  
  21.     CFRunLoopTimerContext timer_context;  
  22.   
  23.     bzero(&source_context, sizeof(source_context));  
  24.     source_context.perform = _perform;  
  25.     source = CFRunLoopSourceCreate(NULL, 0, &source_context);  
  26.     CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopCommonModes);  
  27.   
  28.     bzero(&timer_context, sizeof(timer_context));  
  29.     timer_context.info = source;  
  30.     timer = CFRunLoopTimerCreate(NULL, CFAbsoluteTimeGetCurrent(), 1, 0, 0, 
  31.     _timer, &timer_context);  
  32.     CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopCommonModes);  
  33.   
  34.     CFRunLoopRun();  
  35.   
  36.     return 0;  
  37. }  

 

 

第二個:

 

  1. #include <dispatch/dispatch.h>  
  2. #include <stdio.h>  
  3.   
  4. int  
  5. main()  
  6. {  
  7.     dispatch_source_t source, timer;  
  8.   
  9.     source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0,
  10.     dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));  
  11.     dispatch_source_set_event_handler(source, ^{  
  12.         printf("hello\n");  
  13.     });  
  14.     dispatch_resume(source);  
  15.   
  16.     timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, 
  17.     dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));  
  18.     dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1ull * NSEC_PER_SEC, 0);  
  19.     dispatch_source_set_event_handler(timer, ^{  
  20.         dispatch_source_merge_data(source, 1);  
  21.     });  
  22.     dispatch_resume(timer);  
  23.   
  24.     dispatch_main();  
  25. }  

 

功能是向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://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/Multithreading/RunLoopManagement/RunLoopManagement.html

http://www.wim.me/nsurlconnection-in-its-own-thread/

http://xubenyang.me/384

http://iphonedevelopmentbits.com/event-driven-multitasking-runloopssymbian-ios

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章