iOS关于RunLoop和Timer
轉自:http://www.cnblogs.com/vicstudio/p/3281682.html
RunLoop這個東西,其實我們一直在用,但一直沒有很好地理解它,或者甚至沒有知道它的存在。RunLoop可以說是每個線程都有的一個對象,是用來接受事件和分配任務的loop。永遠不要手動創建一個runloop,它是跟隨著每個線程的。一個RunLoop接收兩種source的事件:input source和timer source。同時必須知道的是,input source,runloop是異步交付的,而timer source是同步交付的。每個runloop都有一個RunLoop Modes,代表它以何種方式執行。
我們為什么從來沒有感覺到runloop的存在呢,是因為當程序啟動,系統默認幫我們啟動了一個主線程的runloop,并且一直在運行,直到程序退出。而用戶創建的子線程,runloop是需要手動啟動的,所以在線程里啟動timer或者調用performSelector: withObject:afterDelay:inModes: 是需要啟動runloop的。在后面我會介紹到怎么啟動。
關于input source :一般來說,input source基本我們用的就是下面幾種方式調用的:
| Methods | Description |
| performSelectorOnMainThread: withObject: waitUntilDone: performSelectorOnMainThread: withObject: waitUntilDone:modes: | Performs the specified selector on the application’s main thread during that thread’s next run loop cycle. These methods give you the option of blocking the current thread until the selector is performed. |
| performSelector: onThread:withObject: waitUntilDone: performSelector: onThread:withObject: waitUntilDone:modes: | Performs the specified selector on any thread for which you have anNSThread?object. These methods give you the option of blocking the current thread until the selector is performed. |
| ? | ? |
| performSelector: withObject: afterDelay: performSelector: withObject: afterDelay:inModes: | Performs the specified selector on the current thread during the next run loop cycle and after an optional delay period. Because it waits until the next run loop cycle to perform the selector, these methods provide an automatic mini delay from the currently executing code. Multiple queued selectors are performed one after another in the order they were queued. |
| cancelPreviousPerformRequestsWithTarget: cancelPreviousPerformRequestsWithTarget: selector:object: | Lets you cancel a message sent to the current thread using the?performSelector: withObject: afterDelay:?orperformSelector: withObject: afterDelay:inModes:method. |
這是系統幫我們封裝了一層,非常容易調用。用戶可以創建自己的Port-based input sources,用來監聽某個端口的事件跟其他線程通信: - (void)addPort:(NSPort *)aPort forMode:(NSString *)mode;- (void)removePort:(NSPort *)aPort forMode:(NSString *)mode;
?
就是利用NSPort對象進行的消息傳遞和delegate,我們一般用不了,有興趣可以看看NSPort的介紹。
?
關于timer source:就是我們平時用到的NSTimer了。
?
至于我們什么時候需要用到runloop呢,主要是下面幾種情況:
1.需要用到NSPort或者其他input source跟其他線程通信。
2.在線程啟動timer。
3.在線程里調用performSelector...這類函數去調用。
?
下面我簡單用一個例子怎么在線程里啟動timer或者performSelector...如下:
-(void)testMain{//開啟一個測試子線程[NSThread detachNewThreadSelector:@selector(threadMethod) toTarget:self withObject:nil];}-(void)threadMethod{//沒用的timer//NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:.2 target:self selector:@selector(timerDone) userInfo:nil repeats:YES];//真正啟動了timerNSTimer *timer = [NSTimerscheduledTimerWithTimeInterval:.2target:selfselector:@selector(timerDone) userInfo:nilrepeats:YES];[[NSRunLoopcurrentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];[[NSRunLoopcurrentRunLoop] run];//同理,調用performSelector也一樣//[self performSelector:@selector(timerDone) withObject:nil afterDelay:.2];//[[NSRunLoop currentRunLoop] run];}-(void)timerDone{NSLog(@"Timer Run");}?
NStimer,幾乎每個做iOS開發的程序員都用過,但是有一個關于Timer的介紹估計很多人都不知道:timer是不一定準時的,是有可能被delay的,每次間隔的時間是不一定一樣的。
A repeating timer reschedules itself automatically based on the scheduled firing time, not the actual firing time. For example, if a timer is scheduled to fire at a particular time and every 5 seconds after that, the scheduled firing time will always fall on the original 5 second time intervals, even if the actual firing time gets delayed. If the firing time is delayed so much that it misses one or more of the scheduled firing times, the timer is fired only once for the missed time period. After firing for the missed period, the timer is rescheduled for the next scheduled firing time.?
簡單解讀一下:就是說一個repeat的timer,它在創建的時候就把每次的執行時間算好了,而不是真正啟動的時候才計算下次的執行時間。舉個例子,假如一個timer在一個特定的時間t激活,然后以間隔5秒的時間重復執行。那么它的執行操作的時間就應該為t, t+5, t+10,... 假如它被延遲了,例如實際上timer在t+2的時候才啟動,那么它下次執行的時間還是t+5,而并不是t+2+5,如果很不幸地在t+5還沒有啟動,那么它理應該在t執行的操作就跟下一次t+5的操作合為一個了。至于為什么會延遲呢,這就跟當前線程的操作有關,因為timer是同步交付的,所以假如當前線程在執行很復雜的運算時,那必須等待運算的完成才能調用timer,這就導致了timer的延遲。
我們就用一個例子來看看效果吧,代碼為:
//這里創建timer以每隔1秒執行[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerDone) userInfo:nil repeats:YES];//這里在第3秒的時候模擬一個復雜運算[self performSelector:@selector(busyDone) withObject:nil afterDelay:3];-(void)busyDone {//這里模擬線程復雜的運算for(NSInteger i = 0; i< 0xffffffff;i++){}NSLog(@"BusgDone"); }-(void)timerDone {NSLog(@"Timer Run"); }?
執行結果為:
?
可以看到,timer本來都是以每隔1秒執行,毫秒都是.564,然后在進行復雜的運算時候,timer直接被delay了,當執行完BusyDone之后,立即執行了TimerRun,然后又在.564執行了TimerRun,而不是距離上次執行時間的1秒。
?
僅供參考。
轉載于:https://www.cnblogs.com/wangpei/p/3686022.html
總結
以上是生活随笔為你收集整理的iOS关于RunLoop和Timer的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 我是SQL小菜鸟---SQL全局临时表防
- 下一篇: ios原子操作和各种锁