iOS開發之Runloop

runloop、autorelease pool以及線程之間的關係。

每一個線程(包含主線程)都有一個Runloop。對於每個Runloop,系統會隱式建立一個Autorelease pool,這樣全部的release pool會構成一個像callstack同樣的一個棧式結構,在每個Runloop結束時,當前棧頂的Autorelease pool會被銷燬,這樣這個pool裏的每一個Object會被release。git

runloop和線程有什麼關係?

總的說來,Run loop,正如其名,loop表示某種循環,和run放在一塊兒就表示一直在運行着的循環。實際上,run loop和線程是緊密相連的,能夠這樣說run loop是爲了線程而生,沒有線程,它就沒有存在的必要。Run loops是線程的基礎架構部分, Cocoa 和 CoreFundation 都提供了 run loop 對象方便配置和管理線程的 run loop (如下都以 Cocoa 爲例)。每一個線程,包括程序的主線程( main thread )都有與之相應的 run loop 對象。 runloop 和線程的關係:github

  1. 主線程的run loop默認是啓動的。 iOS的應用程序裏面,程序啓動後會有一個以下的main()函數
int main(int argc, char * argv[]) {
@autoreleasepool {    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}

重點是UIApplicationMain()函數,這個方法會爲main thread設置一個NSRunLoop對象,這就解釋了:爲何咱們的應用能夠在無人操做的時候休息,須要讓它幹活的時候又能立馬響應架構

  1. 對其它線程來講,run loop默認是沒有啓動的,若是你須要更多的線程交互則能夠手動配置和啓動,若是線程只是去執行一個長時間的已肯定的任務則不須要。
  2. 在任何一個 Cocoa 程序的線程中,均可以經過如下代碼來獲取到當前線程的 run loop 。
NSRunLoop *runloop = [NSRunLoop currentRunLoop];

參考連接:《Objective-C之run loop詳解》函數

runloop的mode做用是什麼?

model 主要是用來指定事件在運行循環中的優先級的,分爲:oop

  • NSDefaultRunLoopMode(kCFRunLoopDefaultMode):默認,空閒狀態
  • UITrackingRunLoopMode:ScrollView滑動時
  • UIInitializationRunLoopMode:啓動時
  • NSRunLoopCommonModes(kCFRunLoopCommonModes):Mode集合

蘋果公開提供的 Mode 有兩個:ui

  1. NSDefaultRunLoopMode(kCFRunLoopDefaultMode)
  2. NSRunLoopCommonModes(kCFRunLoopCommonModes)

以+ scheduledTimerWithTimeInterval...的方式觸發的timer,在滑動頁面上的列表時,timer會暫定回調,爲何?如何解決?

RunLoop只能運行在一種mode下,若是要換mode,當前的loop也須要停下重啓成新的。利用這個機制,ScrollView滾動過程當中NSDefaultRunLoopMode(kCFRunLoopDefaultMode)的mode會切換到UITrackingRunLoopMode來保證ScrollView的流暢滑動:只能在NSDefaultRunLoopMode模式下處理的事件會影響scrllView的滑動。.net

若是咱們把一個NSTimer對象以NSDefaultRunLoopMode(kCFRunLoopDefaultMode)添加到主運行循環中的時候, ScrollView滾動過程當中會由於mode的切換,而致使NSTimer將再也不被調度。線程

同時由於mode仍是可定製的,因此:code

Timer計時會被scrollView的滑動影響的問題能夠經過將timer添加到NSRunLoopCommonModes(kCFRunLoopCommonModes)來解決。代碼以下:對象

// 
// http://weibo.com/luohanchenyilong/ (微博@iOS程序犭袁)
// https://github.com/ChenYilong
 
//將timer添加到NSDefaultRunLoopMode中
[NSTimer scheduledTimerWithTimeInterval:1.0
     target:self
     selector:@selector(timerTick:)
     userInfo:nil
     repeats:YES];
//而後再添加到NSRunLoopCommonModes裏
NSTimer *timer = [NSTimer timerWithTimeInterval:1.0
     target:self
     selector:@selector(timerTick:)
     userInfo:nil
     repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

猜測runloop內部是如何實現的?

通常來說,一個線程一次只能執行一個任務,執行完成後線程就會退出。若是咱們須要一個機制,讓線程能隨時處理事件但並不退出,一般的代碼邏輯 是這樣的:

function loop() {
    initialize();
    do {
        var message = get_next_message();
        process_message(message);
    } while (message != quit);
}

或使用僞代碼來展現下:

// 
// http://weibo.com/luohanchenyilong/ (微博@iOS程序犭袁)
// https://github.com/ChenYilong
int main(int argc, char * argv[]) {
 //程序一直運行狀態
 while (AppIsRunning) {
      //睡眠狀態,等待喚醒事件
      id whoWakesMe = SleepForWakingUp();
      //獲得喚醒事件
      id event = GetEvent(whoWakesMe);
      //開始處理事件
      HandleEvent(event);
 }
 return 0;
}

參考連接: 1. 《深刻理解RunLoop》 1. 摘自博文CFRunLoop,原做者是微博@我就叫Sunny怎麼了

objc使用什麼機制管理對象內存?

經過 retainCount 的機制來決定對象是否須要釋放。 每次 runloop 的時候,都會檢查對象的 retainCount,若是retainCount 爲 0,說明該對象沒有地方須要繼續使用了,能夠釋放掉了。

不手動指定autoreleasepool的前提下,一個autorealese對象在什麼時刻釋放?(好比在一個vc的viewDidLoad中建立)

分兩種狀況:手動干預釋放時機、系統自動去釋放。

  1. 手動干預釋放時機--指定autoreleasepool 就是所謂的:當前做用域大括號結束時釋放。
  2. 系統自動去釋放--不手動指定autoreleasepool Autorelease對象會在當前的 runloop 迭代結束時釋放。 若是在一個vc的viewDidLoad中建立一個 Autorelease對象,那麼該對象會在 viewDidAppear 方法執行前就被銷燬了。 參考連接:黑幕背後的Autorelease
相關文章
相關標籤/搜索