NSRunLoop詳解

1.NSRunLoop是IOS消息機制的處理模式

NSRunLoop的主要作用:控制NSRunLoop里面線程的執行和休眠,在有事情做的時候使當前NSRunLoop控制的線程工作,沒有事情做讓當前NSRunLoop的控制的線程休眠。

2.NSRunLoop 就是一直在循環檢測,從線程start到線程end,檢測inputsource(如點擊,雙擊等操作)同步事件,檢測timesource同步事件,檢測到輸入源會執行處理函數,首先會產生通知,corefunction向線程添加runloop observers來監聽事件,意在監聽事件發生時來做處理。

3.runloopmode是一個集合,包括監聽:事件源,定時器,以及需通知的runloop observers

模式包括:

default模式:幾乎包括所有輸入源(除NSConnection) NSDefaultRunLoopMode模式

mode模式:處理modal panels

connection模式:處理NSConnection事件,屬于系統內部,用戶基本不用

event tracking模式:如組件拖動輸入源 UITrackingRunLoopModes 不處理定時事件

common modes模式:NSRunLoopCommonModes 這是一組可配置的通用模式。將input sources與該模式關聯則同時也將input sources與該組中的其它模式進行了關聯。

4.每次運行一個run loop,你指定(顯式或隱式)run loop的運行模式。當相應的模式傳遞給run loop時,只有與該模式對應的 input sources才被監控并允許run loop對事件進行處理(與此類似,也只有與該模式對應的observers才會被通知)

5.NSTimer默認添加到當前NSRunLoop中,也可以手動制定添加到自己新建的NSRunLoop的中

[NSTimer schduledTimerWithTimeInterval: target:selector:userInfo:repeats];

此方法默認添加到當前NSRunLoop中

NSTimer *timer = [NSTimer timerWithTimeInterval: invocation:repeates:];

NSTimer *timer = [[NSTimer alloc] initWithFireDate:...];

創建timer [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

注意 timer的釋放

例:

1). 在timer與table同時執行情況,當拖動table時,runloop進入UITrackingRunLoopModes模式下,不會處理定時事 件,此時timer不能處理,所以此時將timer加入到NSRunLoopCommonModes模式(addTimer forMode)

2).在滾動一個頁面時來松開,此時connection不會收到消息,由于scroll時runloop為UITrackingRunLoopModes模式,不接收輸入源,此時要修改connection的mode

[scheduleInRunLoop:[NSRunLoop currentRunLoop]forMode:NSRunLoopCommonModes];

6、子線程中的NSRunLoop需要手動啟動,在子線程中使用timer要啟動NSRunLoop。

7、關于-(BOOL)runMode:(NSString *)mode beforeDate:(NSDate *)date;方法

指定runloop模式來處理輸入源,首個輸入源或date結束退出。

暫停當前處理的流程,轉而處理其他輸入源,當date設置為NSDate distantFuture,所以除非處理其他輸入源結束,否則永不退出處理暫停的當前處理的流程。

8.while(A){

[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];

}

當前A為YES時,當前runloop會一直接收處理其他輸入源,當前流程不繼續處理,出為A為NO,當前流程繼續

9 、perform selector在thread中被序列化執行,這樣就緩和了許多在同一個thread中運行多個方法所產生的同步問題。perform selector source在運行完selector后自動從run loop中移除。

當 在非main thread中perform selector時,其thread中必須有一個激活的run loop。對于你自己創建的thread而 言,只有你的代碼顯式的運行一個run loop后該perform selector才能得到執行。Run loop在當loop運行時處理所有已排隊 的perform selector,而不是在一個loop循環時只處理某一個perform selector。

10.performSelector 關于內存管理的執行原理是這樣的執 行 [self performSelector:@selector(method1:) withObject:self.tableLayer afterDelay:3]; 的 時候,系統會將tableLayer的引用計數加1,執行完這個方法時,還會將tableLayer的引用計數減1,由于延遲這時tableLayer的 引用計數沒有減少到0,也就導致了切換場景dealloc方法沒有被調用,出現了內存泄露。

利用如下函數:

[NSObject cancelPreviousPerformRequestsWithTarget:self]

當然你也可以一個一個得這樣用:

[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(method1:) object:nil]

加上了這個以后,順利地執行了dealloc方法

在touchBegan里面

[self performSelector:@selector(longPressMethod:) withObject:nil afterDelay:longPressTime]

然后在end 或cancel里做判斷,如果時間不夠長按的時間調用:

[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(longPressMethod:) object:nil]

取消began里的方法

**********************************以下是我在cocoachina中看到的一份總結 轉載過來

線程實現的幾種方式:

  1. Operation Objects // NSOperation及相關子類
  2. ***** // dispatch_async等相關函數
  3. Idle-time notifications // NSNotificationQueue,低優先級
  4. Asynchronous functions // 異步函數
  5. Timers // NSTimer
  6. Separate processes // 沒用過

線程創建的成本:
kernel data structures 約1KB
Stack space 512KB(secondary threads)
1MB(iOS main thread)
Creation time 約90 microseconds

Run Loop和線程的關系:

  1. 主線程的run loop默認是啟動的,用于接收各種輸入sources
  2. 對第二線程來說,run loop默認是沒有啟動的,如果你需要更多的線程交互則可以手動配置和啟動,如果線程執行一個長時間已確定的任務則不需要。

Run Loop什么情況下使用:
a. 使用ports 或 input sources 和其他線程通信 // 不了解
b. 在線程中使用timers // 如果不啟動run loop,timer的事件是不會響應的
c. 在Cocoa 應用中使用performSelector...方法 // 應該是performSelector...這種方法會啟動一個線程并啟動run loop吧
d. 讓線程執行一個周期性的任務 // 如果不啟動run loop, 線程跑完就可能被系統釋放了

注:timer的創建和釋放必須在同一線程中。
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]; 此方法會retain timer對象的引用計數

原文地址:http://www.lanou3g.com/blog/sort/Developerdiary/page/3

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容