runloop

  1. 首先看兩個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://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

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