NSRunLoop概述和原理
2013-01-09 10:58 三戒1993 阅读(153) 评论(0) 编辑 收藏 举报首先讲NSRunLoop之前, 说说timer这个东西:
我们把环境都设置在Cocoa中,这里所讲的timer就用NStimer,当然这里的原理适用于其他系统的timer。
因为NSTimer是作为一种timer
resource加入到NSRunLoop中去,在当timer的时间累计到规定时间之后就触发timer的action。从这个过程上看来timer应该是很“准时”的,而且现实情况也是这样的,比如一个规定每1s触发的timer绝大多数情况一般也是1s触发一次。但是timer的这种所谓的“准时”千万不要让你产生这样一种幻觉,“timer可以用来作精确的循环控制,比如用来精准控制动画”。
timer的不精确性主要是表现在:timer有可能delay或者丢失。具体有下面几种情形:
-
runloop被堵塞了。timer被加入到runloop中去,如果这个runloop堵塞了,举个例子说就是处理runloop的某个resource花了10S钟,而你的timer是1s触发一次,那么这个时候因为runloop被这个10s的任务所堵塞住了,就没有可能去处理timer了,于是按照Thread
Programming Guide原文中的说法就是:“if a timer fires when the run loop
is in the middle of executing a handler routine, the timer waits
until the next time through the run loop to invoke its handler
routine. If the run loop is not running at all, the timer never
fires.” 所以这种情况下,timer可能被delay甚至是丢失掉。 -
runloop没有run或者run的model timer不支持。加入timer加入的是defaule
mode,但是这个时候用户在如NSRunLoop概述和原理中第一段代码中,用的是某个用户自己定于的mode在run这个runloop那么timer的计时就没有被累加。之有当runloop的model支持该timer的时候,该timer计时才会累计。
所以timer只是一种非实时控制的,“粗略”地计时的一种工具,在通常我们对实时不太要求的时候timer满足我们的需求,但是如果对实时要求很高,比如游戏中,就得采取一些真正实时的手段来实现了。这里我想起了很早的时候看过的一份有戏代码,其中的动画效果都是由NSTimer来控制的,当时我就石化了,虽然游戏各种动画都还能看,但是明显不是很流畅,而且时快时慢。
结合上面说的,又会过头看看SDL中对timer的实现就实在是太简陋了,不过这种简单的timer系统有的时候反而能够提供很好的实时性。
十二 12
1.什么是NSRunLoop?
我们会经常看到这样的代码:
1
2
3
4
5
6
7
8
9
10 |
- (IBAction)start:(id)sender {
pageStillLoading = YES; |
这段代码很神奇的,因为他会“暂停”代码运行,而且程序运行不会因为这里有一个while循环而受到影响。在[progress
setHidden:NO]执行之后,整个函数想暂停了一样停在循环里面,等loadPageInBackground里面的操作都完成了以后才让[progress
setHidden:YES]运行。这样做就显得简介,而且逻辑很清晰。如果你不这样做,你就需要在loadPageInBackground里面表示load完成的地方调用[progress
setHidden:YES],显得代码不紧凑而且容易出错。
那么具体什么是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中截取):
1
2
3
4
5
6
7
8
9 |
int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow){
…
TranslateMessage(&msg);
DispatchMessage(&msg); |
可以看到在GetMessage之后就去分发处理消息了,而iOS中main函数中只是调用了UIApplicationMain,那么我们可以介意猜出UIApplicationMain在初始化完成之后就会进入这样一个情形:
1
2
3
4
5
6
7 |
int UIApplicationMain(…){
… |