iOS開發中對RunLoop的我的心得

 

從接觸iOS到如今也有將近兩年了,對iOS中的RunLoop也有了必定的認識,下面講講我的對RunLoop的理解html

 

  初識RunLoop程序員

 

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

咱們通常程序就是執行一個線程,是一條直線.有起點終點.而runloop就是一直在線程上面畫圓圈,一直在跑圈,除非切斷不然一直在運行。網上說的比喻很好,直線就像曇花一現同樣,圓就像OS,一直運行直到你關機爲止。網絡

 

  RunLoop資料app

 

    蘋果官方文檔:框架

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

     

     CFRunLoopRef是開源的:動畫

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

 

 

 

  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,而後重啓新的Loop

NSDefalutRunLoopMode      默認狀態.空閒狀態
UITrackingRunLoopMode     滑動ScrollView
UIInitializationRunLoopMode    私有,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結束。

   

好的文章都是值得反覆看的,咱們在不一樣的階段來相同的文章或資料都能有不一樣的收穫,
提升本身對知識的理解,聲明一下:最好是本身理解後再總結一次,不要一味的收藏,
每一個程序員都有着成爲大牛的潛質,只在是否努力。加油 技術宅們!
相關文章
相關標籤/搜索