IOS開發之nsrunloop開發指南

來源:互聯網
上載者:User

首先來一個簡單的Demo

我們會經常看到這樣的代碼:

- (IBAction)start:(id)sender 

pageStillLoading = YES; 

[NSThread detachNewThreadSelector:@selector(loadPageInBackground:)toTarget:self withObject:nil]; 

[progress setHidden:NO]; 

while (pageStillLoading) { 

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

[progress setHidden:YES]; 


複製代碼這段代碼很神奇的,因為他會“暫停”代碼運行,而且程式運行不會因為這裡有一個while迴圈而受到影響。在[progress setHidden:NO]執行之後,整個函數想暫停了一樣停在迴圈裡面,等loadPageInBackground裡面的操作都完成了以後才讓[progress setHidden:YES]運行。這樣做就顯得簡介,而且邏輯很清晰。如果你不這樣做,你就需要在loadPageInBackground裡面表示load完成的地方調用[progress setHidden:YES],顯得代碼不緊湊而且容易出錯。
[iGoogle有話說:應用程式架構主線程已經封裝了對NSRunLoop runMode:beforeDate:的調用;它和while迴圈構成了一個訊息泵,不斷擷取和處理訊息;可能大家會比較奇怪,既然主線程中已經封裝好了對NSRunLoop的調用,為什麼這裡還可以再次調用,這個就是它與Windows訊息迴圈的區別,它可以嵌套調用.當再次調用while+NSRunLoop時候程式並沒有停止執行,它還在不停提取訊息/處理訊息.這一點與Symbian中Active Scheduler的嵌套調用達到同步作用原理是一樣的.]

 

 

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

NSRunLoop的作用在於有事情做的時候使的當前NSRunLoop的線程工作,沒有事情做讓當前NSRunLoop的線程休眠

 


2.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的釋放

 


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

 


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

模式包括:

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


mode模式:處理modal panels

connection模式:處理NSConnection事件,屬於系統內部,使用者基本不用

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

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

 

 

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

 

 

 

 


例:

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

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

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

 


5.關於-(BOOL)runMode:(NSString *)mode beforeDate:(NSDate *)date;方法

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

暫停當前處理的流程,轉而處理其他輸入源,當date設定為[NSDate distantFuture](將來,基本不會到達的時間),所以除非處理其他輸入源結束,否則永不退出處理暫停當前處理的流程。

 


6.while(A){

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


}

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

 


7.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。

 


8.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,低優先順序
3. Asynchronous functions  // 非同步函數
4. Timers                      // NSTimer
5. 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對象的引用計數。


 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.