NSRunLoop的進一步了解
2011-8-22 15:42| 釋出者: Vincent| 檢視: 716| 評論: 17|原作者: iGoogle
摘要: 本文基于一篇網絡文章,加入了一些自己的了解,希望對大家有所幫助 iPhone應用開發中關于NSRunLoop的概述是本文要介紹的内容,NSRunLoop是一種更加高明的消息處理模式,他就高明在對消息處理過程進行了更好的抽象和 ...
本文基于一篇網絡文章,加入了一些自己的了解,希望對大家有所幫助 iPhone應用開發中關于NSRunLoop的概述是本文要介紹的内容,NSRunLoop是一種更加高明的消息處理模式,他就高明在對消息處理過程進行了更好的抽象和封裝,這樣才能是的你不用處理一些很瑣碎很低層次的具體消息的處理,在NSRunLoop中每一個消息就被打包在input source或者是timer source中了,來看詳細内容。 1.什麼是NSRunLoop 我們會經常看到這樣的代碼:
複制代碼 這段代碼很神奇的,因為他會“暫停”代碼運作,而且程式運作不會因為這裡有一個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的嵌套調用達到同步作用原理是一樣的.] 那麼具體什麼是NSRunLoop呢?其實NSRunLoop的本質是一個消息機制的處理模式。如果你對vc++程式設計有一定了解,在windows中,有一系列很重要的函數SendMessage,PostMessage,GetMessage,這些都是有關消息傳遞處理的API。 但是在你進入到Cocoa的程式設計世界裡面,我不知道你是不是走的太快太匆忙而忽視了這個很重要的問題,Cocoa裡面就沒有提及到任何關于消息處理的API,開發者從來也沒有自己去關心過消息的傳遞過程,好像一切都是那麼自然,像大自然一樣自然?在Cocoa裡面你再也不用去自己定義WM_COMMAD_XXX這樣的宏來辨別某個消息,也不用在switch-case裡面去對特定的消息做特别的處理。難道是Cocoa裡面就沒有了消息機制?答案是否定的,隻是Apple在設計消息處理的時候采用了一個更加高明的模式,那就是RunLoop。 2. NSRunLoop工作原理 接下來看一下NSRunLoop具體的工作原理,首先是官方文檔提供的說法,看圖: 通過所有的“消息”都被添加到了NSRunLoop中去,而在這裡這些消息并分為“input source”和“Timer source” 并在循環中檢查是不是有事件需要發生,如果需要那麼就調用相應的函數處理。為了更清晰的解釋,我們來對比VC++和iOS消息處理過程。 VC++中在一切初始化都完成之後程式就開始這樣一個循環了(代碼是從戶sir mfc程式設計課程的slides中截取):
複制代碼 是以在UIApplicationMain中也是同樣在不斷處理runloop才是的程式沒有退出。剛才的我說了NSRunLoop是一種更加高明的消息處理模式,他就高明在對消息處理過程進行了更好的抽象和封裝,這樣才能是的你不用處理一些很瑣碎很低層次的具體消息的處理,在NSRunLoop中每一個消息就被打包在input source或者是timer source中了,當需要處理的時候就直接調用其中包含的相應對象的處理函數了。 是以對外部的開發人員來講,你感受到的就是,把source/timer加入到runloop中,然後在适當的時候類似于[receiver action]這樣的事情發生了。甚至很多時候,你都沒有感受到整個過程前半部分,你隻是感覺到了你的某個對象的某個函數調用了。 比如在UIView被觸摸時會用touchesBegan/touchesMoved等等函數被調用,也許你會想,“該死的,我都不知道在那裡被告知有觸摸消息,這些處理函數就被調用了!?”是以,消息是有的,隻是runloop已經幫你做了!為了證明我的觀點,我截取了一張debug touchesBegan的call stack,有圖有真相,如圖: |
收藏 分享 發表評論
最新評論
- g3ee 2011-9-7 18:13
-
rongjianxing 發表于 2011-9-7 17:31
頂牛人”比如在UIView被觸摸時會用touchesBegan/touchesMoved等等函數被調用,也許你會想,“該死的,我都不知道在 ...NSRunLoop的進一步了解 NSRunLoop的進一步了解
- rongjianxing 2011-9-7 17:31
-
”比如在UIView被觸摸時會用touchesBegan/touchesMoved等等函數被調用,也許你會想,“該死的,我都不知道在那裡被告知有觸摸消息,這些處理函數就被調用了!“
在win中,如果使用純api手工打造,的确沒有這功能。
但使用mfc,wtl等類庫,OnCreate()等函數也是一樣”都不知道在那裡被告知有消息,這些處理函數就被調用了“
- rongjianxing 2011-9-7 17:28
-
",Cocoa裡面就沒有提及到任何關于消息處理的API,開發者從來也沒有自己去關心過消息的傳遞過程,好像一切都是那麼自然,像大自然一樣自然?在Cocoa裡面你再也不用去自己定義WM_COMMAD_XXX這樣的宏來辨別某個消息,也不用在switch-case裡面去對特定的消息做特别的處理。"
這個說法也有問題,cocoa與win的開發者都要關心消息的處理,隻是在windows下拉使用api時,要做WM_COMMAD_XXX和消息函數對應起來,而cocoa是實作特定接口的delegate與引起消息的源對應起來。
而通過使用ide,都可以通過拉拖點選來完成對應操作。
- rongjianxing 2011-9-7 17:13
-
“可能大家會比較奇怪,既然主線程中已經封裝好了對NSRunLoop的調用,為什麼這裡還可以再次調用,這個就是 它與Windows消息循環的差別,它可以嵌套調用.”
這句不準确,windows的消息循環也可以嵌套調用,比如win處理拖動選擇時可以這樣實作:
- case WM_LBUTTONDOWN:
- {
- GetCapture();
- while (GetMessage (&msg, NULL, 0, 0)) // -------開始選擇------
- {
- if (WM_MOUSEMOVE == msg.message)
- {
- // 畫選擇框
- }
- if (WM_LBUTTONUP == msg.message)
- {
- // 畫選擇框
- ReleaseCapture ();
- break; // 跳出循環
- }
- } // while 結束. -------結束選擇-------
- }
- bishop 2011-9-7 11:45
- mark 學習了
- pxfokko 2011-9-6 16:39
- 學習了
NSRunLoop的進一步了解 NSRunLoop的進一步了解 NSRunLoop的進一步了解 NSRunLoop的進一步了解 NSRunLoop的進一步了解 NSRunLoop的進一步了解
- ericni 2011-9-1 11:06
- 有點懂了,多謝
- snakeninny 2011-8-26 10:56
- 支援一下!小弟還看不懂……
- iGoogle 2011-8-26 10:12
-
happyboyxq 發表于 2011-8-26 10:01
我還有點不明白,從這個方法來看,調用start函數的輸入源(暫稱為輸入源1),此時輸入源1應該是擁有運作循環 ...NSRunLoop的進一步了解 NSRunLoop的進一步了解 他們是不同的線程,
新啟動的線程(稱為線程1)根本不在主線程(我們姑且稱start函數執行的線程為主線程)中執行。
主線程和線程1的切換執行是cpu排程的事
這裡的NSRunLoop是主線程中的消息循環機制,每個線程都有自己的NSRunLoop
- happyboyxq 2011-8-26 10:01
-
我還有點不明白,從這個方法來看,調用start函數的輸入源(暫稱為輸入源1),此時輸入源1應該是擁有運作循環的控制權的(文檔上說運作循環會将控制權交給使用者的)
- (IBAction)start:(id)sender
{
pageStillLoading = YES;
此處又建立了一個線程,從代碼會在下面的運作循環處停止可知,該線程為輸入源2,那何時這個輸入源2會擁有運作循環的控制權并執行函數呢?此時的輸入源1并未執行完成,應該不會歸還控制權給運作循環才對啊。這樣不是陷入了一個循環嗎,輸入源1未交出控制權,輸入源2在等待控制權,那此時程式是怎麼執行到最後的呢,pageStillLoading設為NO應該是在輸入源2裡面做的。這表示中間應該有某個過程把輸入源1的控制權交給了輸入源2,我就是想請教一下這個過程是在哪,什麼時候執行的。
[NSThread detachNewThreadSelector:@selector(loadPageInBackground:)toTarget:self withObject:nil];
[progress setHidden:NO];
while (pageStillLoading) {
此處調用這個方法是否就是輸入源1為了交出控制權呢?這樣輸入源2就有機會執行,待執行完成後退出,pageStillLoading=NO,因為輸入源1仍存在于運作循環中,是以繼續執行,這樣後面的代碼才得以執行呢?
[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
[progress setHidden:YES];
}
- cheungching 2011-8-25 20:45
- 為什麼在UIApplicationDelegate中做這個會出現一會黑屏呢?!
- cheungching 2011-8-25 20:04
- 呵呵,分析的太好了。
- dymx101 2011-8-24 17:17
- 學習了
NSRunLoop的進一步了解 NSRunLoop的進一步了解
- iGoogle 2011-8-24 11:57
-
- [NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- iGoogle 2011-8-24 11:55
-
happyboyxq 發表于 2011-8-24 09:47
NSRunLoop的進一步了解 NSRunLoop的進一步了解 while (pageStillLoading) {
[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NS ...
不是一直等待,實際上它還在處理消息,界面不會停止響應,
它的作用是同步,隻是不執行while循環後面跟着的語句.
- happyboyxq 2011-8-24 09:47
-
while (pageStillLoading) {
[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
裡的NSRunLoop應該是主線程的運作循環吧,這樣主線程不是一直處于等待狀态?如果我想做點别的什麼怎麼辦呢?再啟一個線程?
- pp_psy 2011-8-22 20:08
- 頂,多謝iGoogle哥
檢視全部評論(17)