iOS開發中對RunLoop的個人心得

來源:互聯網
上載者:User

標籤:initial   階段   連接埠   current   程式員   dev   主線程   技術   好的   

 

從接觸iOS到現在也有將近兩年了,對iOS中的RunLoop也有了一定的認識,下面講講個人對RunLoop的理解

 

  初識RunLoop

 

 RunLoops是與線程相關聯的基礎部分,一個Run Loop就是事件處理迴圈,他是用來調度和協調接收到的事件處理。使用RunLoop的目的,就是使的線程有工作需要做的時候忙碌起來,當沒事做的時候,又可以使得線程休眠。

我們一般程式就是執行一個線程,是一條直線.有起點終點.而runloop就是一直線上程上面畫圓圈,一直在跑圈,除非切斷否則一直在運行。網上說的比喻很好,直線就像曇花一現一樣,圓就像OS,一直運行直到你關機為止。

 

  RunLoop資料

 

    蘋果官方文檔:

https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Multithreading/RunLoopManagement/RunLoopManagement.html

     

     CFRunLoopRef是開源的:

http://opensource.apple.com/source/CF/CF-1151.16/

 

 

 

  RunLoop對象

 

   iOS中有兩套API來訪問和使用RunLoop

 

  • Foundation架構 --> NSRunLoop
  • Core Foundation架構 -->CFRunLoopRef

 

NSRunLoop和CFRunLoopRef都代表著RunLoop對象
NSRunLoop是基於CFRunLoopRef的一層OC封裝, 所以要瞭解RunLoop內部結構, 需要多研究CFRunLoopRef層面的API(Core Foundation層面)

 

 

 

   RunLoop與線程

 

  • 每條線程都有唯一的一個與之對應的RunLoop對象(如果我也想開一個子線成,並且讓線程不死,則子線程開一個RunLoop)
  • 主線程的RunLoop已經自動建立好了,子線程的RunLoop需要主動建立
  • RunLoop在第一次擷取時建立,線上程結束時銷毀

 

    

   獲得RunLoop對象

 

  • Foundation
[NSRunLoop currentRunLoop]; // 獲得當前線程的RunLoop對象[NSRunLoop mainRunLoop]; // 獲得主線程的RunLoop對象
  • Core Foundation
CFRunLoopGetCurrent(); // 獲得當前線程的RunLoop對象CFRunLoopGetMain(); // 獲得主線程的RunLoop對象

    如果在主線程中: 當前線程的RunLoop對象和主線程的RunLoop對象取得的是相同的。

 

   CFRunLoopSourceRef

  • CFRunLoopModeRef代表RunLoop的運行模式
  • 一個RunLoop包含若干個Mode,每個Mode又包含若干個Source/Timer/Observer
  • 每次RunLoop啟動時,只能指定其中一個 Mode,這個Mode被稱作 CurrentMode(可以擷取到[NSRunLoop currentRunLoop].currentMode)
  • 如果需要切換Mode,只能退出Loop再重新指定一個Mode進入(因為RunLoop是一個運行迴圈, 一直在跑圈, 換另一個模式,必須先退出, 然後按照另一個模式跑圈)
  • 這樣做主要是為了分隔開不同組的Source/Timer/Observer,讓其互不影響(切換模式是為了,讓它按照另一個模式的Source,Timer,Observer來跑圈, 互不影響)

RunLoop 啟動必須要傳入一個模式,RunLoop有多個模式, 但是每次只能運行一種模式

   

     RunLoop定義兩個Version的Source

  • Source0:處理App內部事件,App自己負責管理(觸發),如UIEvent,CFSocket
  • Source1:由RunLoop和核心管理,Mach port驅動 如CFMach、CFMessage

 

   CFRunLoopObserverRef

      向內部報告RunLoop目前狀態的更改 CAAnimation

      可以監聽的時間點如下幾點:

      

    RunLoopObserver 與 Autorelease Pool

   

UIKit通過RunLoopObserver在RunLoop兩次Sleep間對AutoreleasePool進行pop和push,將這次Loop中產生的Autorelease對象釋放。(好像swift中沒有關於釋放的問題)

  

CFRunLoopModeRef

      

RunLoop在同一時段只能且必須在一種特定Mode下Run更換Mode時, 需要暫停當前的Loop,然後重啟新的LoopNSDefalutRunLoopMode? ? ? 預設狀態.空閑狀態UITrackingRunLoopMode? ? ?滑動ScrollViewUIInitializationRunLoopMode? ? 私人,App啟動時NSRunLoopCommonModes? ? ?預設包括上面第一和第二

  

 CFRunLoopTimerRef
  • CFRunLoopTimerRef是基於時間的觸發器(基本上說的就是NSTimer), 一個模式下可以有多個Timer(Arrar中存放)
 /**     *  這個方法內部實現是: 建立timer,添加到RunLoop中的預設的Mode中,RunLoop啟動這個mode,取出這個mode中timer來用     */    [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(run) userInfo:nil repeats:YES];    /**     *  上面的代碼等同於下面的     */    // 建立Timer    NSTimer *timer = [NSTimer timerWithTimeInterval:0.5 target:self selector:@selector(run) userInfo:nil repeats:YES];    // 定時器只運行在 NSDefaultRunLoopMode 模式下, 一旦RunLoop進入其他模式,這個定時器就不會工作    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];    // 如果拖動時, 我們將定時器添打上這個NSRunLoopCommonModes的標記    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];     NSLog(@"-----------%@", [NSRunLoop currentRunLoop]);   /**     *  定時器會跑在標記為common modes的模式下(這個模式只是個標記)     *  RunLoop會尋找帶有common標籤的模式,有這個標籤的,都可以跑     *  列印當前的RunLoop資訊輸出為:(有common modes標籤的有兩個,UITrackingRunLoopMode和kCFRunLoopDefaultMode),所以定時器可以在這兩個模式下跑, RunLoop只會運行一種模式     common modes = <CFBasicHash 0x7fb8b2700490 [0x10ec6ba40]>{type = mutable set, count = 2,     entries =>     0 : <CFString 0x10fba2210 [0x10ec6ba40]>{contents = "UITrackingRunLoopMode"}     2 : <CFString 0x10ec8c5e0 [0x10ec6ba40]>{contents = "kCFRunLoopDefaultMode"}     }     */

 

 AFNetWorking 中建立RunLoop

     

 [[NSThread currentThread] setName:@"AFNetworking"];NSRunLoop *runloop = [NSRunLoop currentRunLoop];[runLoop addPort:[NSMachPort port] forMode:NSDefalutRunLoopMode]//一直活著[runLoop run];

    這在處理網路響應是一個很好的方法

 

  UITrackingRunLoopMode 與 NSTimer

 

  

// 預設情況下NSTimer被加入NSDefalutRunLoopMode//如果想NSTimer受到組件或者動畫影響 添加到NSRunLoopCommonModes [[NSRunLoop currentRunLoop]addTimer:timer...forMode:NSRunLoopCommonModes];

 

RunLoop的處理邏輯是什麼呢?

  

    每次運行run loop,你線程的run loop對會自動處理之前未處理的訊息,並通知相關的觀察者。具體的順序如下:

  1. 通知觀察者run loop已經啟動
  2. 通知觀察者任何即將要開始的定時器
  3. 通知觀察者任何即將啟動的非基於連接埠的源
  4. 啟動任何準備好的非基於連接埠的源
  5. 如果基於連接埠的源準備好並處於等待狀態,立即啟動;並進入步驟9。
  6. 通知觀察者線程進入休眠
  7. 將線程置於休眠直到任一下面的事件發生:
    • 某一事件到達基於連接埠的源
    • 定時器啟動
    • Run loop設定的時間已經逾時
    • run loop被顯式喚醒
  8. 通知觀察者線程將被喚醒。
  9. 處理未處理的事件
    • 如果使用者定義的定時器啟動,處理定時器事件並重啟run loop。進入步驟2
    • 如果輸入源啟動,傳遞相應的訊息
    • 如果run loop被顯式喚醒而且時間還沒逾時,重啟run loop。進入步驟2
  10. 通知觀察者run loop結束。

   

好的文章都是值得反覆看的,我們在不同的階段來相同的文章或資料都能有不同的收穫,提高自己對知識的理解,聲明一下:最好是自己理解後再總結一次,不要一味的收藏,每個程式員都有著成為大牛的潛質,只在是否努力。加油 技術宅們!

  

   


 

  

 

iOS開發中對RunLoop的個人心得

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.