原文地址:http://www.cnblogs.com/tangbinblog/archive/2012/12/07/2807088.html
iOS RunLoop 初识
今天突然才之间才意识到NSTimer这样的运行方式,是在多线程中实现的循环还是在主线程中去实现的呢。当然不可能是在主线程中的while那么简单,那样什么都干不了,简单看了下NSTimer是以同步方式运行的。时间到了,消息发出后,ontimer的函数是在主线程上调用的。
我们会经常看到这样的代码:
- - (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],显得代码不紧凑而且容易出错。
Run loop就像它的名字一样,是你thread中的一个循环并对收到的事件进行处理。你的代码提供控制语句用来对run loop进行执行——换句话说:你的代码提供while或for循环来驱动run loop。在你的循环中,你使用run loop对象来“运行”事件处理代码。事件处理代码主要进行接收事件并调用事件处理函数。
Run loop从两个不同的事件源中接收消息。Input sources(CFRunLoopSource)投递异步消息,通常来自于另一个thread或另一个应用程序。Timer sources(CFRunLoopTimer)当在计划的时间或重复的时间间隔内投递同步消息。两种事件源都使用应用程序指定的处理方式对到达的事件进行处理。下图展示了run loop和不同的事件源结构。
如果我们要写多线程的程序,可能就需要自己来管理Run Loop。
下面说一下楼主提出的方法中的参数:
RunMode: NSDefaultRunLoopMode,可以把这个理解为一个”过滤器“,我们可以只对自己关心的事件进行监视。一般NSDefaultRunLoopMode是最常用的。
启动run loop的方法就是lz写的这个,它的说明如下:
Runs the loop once, blocking for input in the specified mode until a given date.
启动run loop一次,在特定的run loop mode下等待输入。
如果没有附加input source或是timer,或是过limitDate,run loop就会退出,并且方法返回NO。
下来是Run Loop的使用场合:
1. 使用port或是自定义的input source来和其他线程进行通信
2. 在线程(非主线程)中使用timer
3. 使用 performSelector…系列(如performSelectorOnThread, …)
4. 使用线程执行周期性工作
run loop不需要创建,在线程中只需要调用[NSRunLoop currentRunLoop]就可以得到
假设我们想要等待某个异步方法的回调。比如connection。如果我们的线程中没有启动run loop,是不会有效果的(因为线程已经运行完毕,正常退出了)。
何时使用 Run Loop
仅当在为你的程序创建辅助线程的时候,你才需要显式运行一个 run loop。Run loop 是程序主线程基础设施的关键部分。所以,Cocoa 和 Carbon 程序提供了代码运 行主程序的循环并自动启动 run loop。IOS 程序中 UIApplication 的 run 方法(或 Mac OS X 中的 NSApplication)作为程序启动步骤的一部分,它在程序正常启动的时 候就会启动程序的主循环。类似的,RunApplicationEventLoop 函数为 Carbon 程序 启动主循环。如果你使用 xcode 提供的模板创建你的程序,那你永远不需要自己去显 式的调用这些例程。
对于辅助线程,你需要判断一个 run loop 是否是必须的。如果是必须的,那么 你要自己配置并启动它。你不需要在任何情况下都去启动一个线程的 run loop。比 如,你使用线程来处理一个预先定义的长时间运行的任务时,你应该避免启动 run loop。Run loop 在你要和线程有更多的交互时才需要,比如以下情况:
使用端口或自定义输入源来和其他线程通信 使用线程的定时器 Cocoa 中使用任何 performSelector...的方法 使线程周期性工作
如果你决定在程序中使用 run loop,那么它的配置和启动都很简单。和所有线程 编程一样,你需要计划好在辅助线程退出线程的情形。让线程自然退出往往比强制关 闭它更好。关于更多介绍如何配置和退出一个 run loop,参阅”使用 Run Loop 对象” 的介绍。
上代码:
使用runloop阻塞线程的正确写法
Runloop可以阻塞线程,等待其他线程执行后再执行。
比如:
@implementation ViewController{
BOOL end;
}
…
– (void)viewDidLoad
{
[super viewDidLoad];
NSLog(@”start new thread …”);
[NSThread detachNewThreadSelector:@selector(runOnNewThread) toTarget:self withObject:nil];
while (!end) {
NSLog(@”runloop…”);
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
NSLog(@”runloop end.”);
}
NSLog(@”ok.”);
}
-(void)runOnNewThread{
NSLog(@”run for new thread …”);
sleep(1);
end=YES;
NSLog(@”end.”);
}
但是这样做,运行时会发现,while循环后执行的语句会在很长时间后才被执行。
那是不是可以这样:
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
缩短runloop的休眠时间,看起来解决了上面出现的问题。
不过这样也又问题,runloop对象被经常性的唤醒,这违背了runloop的设计初衷。runloop的作用就是要减少cpu做无谓的空转,cpu可在空闲的时候休眠,以节约电量。
那么怎么做呢?正确的写法是:
-(void)runOnNewThread{
NSLog(@”run for new thread …”);
sleep(1);
[self performSelectorOnMainThread:@selector(setEnd) withObject:nil waitUntilDone:NO];
NSLog(@”end.”);
}
-(void)setEnd{
end=YES;
}
见黑体斜体字部分,要将直接设置变量,改为向主线程发送消息,执行方法。问题得到解决。
这里要说一下,造成while循环后语句延缓执行的原因是,runloop未被唤醒。因为,改变变量的值,runloop对象根本不知道。延缓的时长总是不定的,这是因为,有其他事件在某个时点唤醒了主线程,这才结束了while循环。那么,向主线程发送消息,将唤醒runloop,因此问题就解决了。
相关推荐
总的来说,理解和熟练运用CFRunLoop和NSRunLoop对于优化iOS和Mac OS X应用程序的性能至关重要。它们是系统级的事件处理机制,能够有效提升用户体验,减少不必要的CPU占用,并保证应用程序的响应速度。通过深入学习这...
综上所述,`NSRunLoopDemo`提供了丰富的示例,帮助开发者深入理解`NSRunLoop`的工作原理及其在实际开发中的应用。通过学习这个项目,你可以掌握如何有效地使用`NSRunLoop`来提升应用程序的性能和用户体验。
LightWeightRunLoop-A-Reactor-Style-NSRunLoop, NSRunLoop反应器样式实现 LightWeightRunLoop在其他线程,定时器,URLConnection,LWStream ( LWInputStream、LWOutputStream ),LWPort ( LWSocketPort ) 等上实现 ...
Run Loop的配置和管理可以通过Objective-C的CFRunLoopRef(Core Foundation层)和NSRunLoop(Foundation层)进行。开发者可以通过添加源(Sources)、观察者(Observers)和端口(Ports)来定制Run Loop的行为,例如...
首先,让我们理解`NSThread`。`NSThread`是Objective-C中的线程类,用于实现多线程编程。每个应用程序都有一个主线程,通常用于处理用户界面交互。当创建一个新的`NSThread`实例时,你可以定义一个入口点方法,该...
在 iOS 开发中,事件循环机制扮演着至关重要的角色,其中 NSRunLoop 是一个核心组件,负责管理和处理事件。本文将深入探讨 NSRunLoop 的工作原理和实现机制。 一、什么是 NSRunLoop? NSRunLoop 是一种高明的消息...
NSRunLoop的基本使用:通过`[[NSRunLoop mainRunLoop] runUntilDate:]`或`[[NSRunLoop mainRunLoop] run]`启动运行循环。 - B. NSRunLoop的模式:NSRunLoop有多个运行模式(如NSDefaultRunLoopMode、...
在iOS和macOS开发中,理解并有效使用线程管理技术是至关重要的。`NSThread`、`NSRunLoop`和`Dispatch Queue`是Apple的Foundation框架中用于多线程和异步任务处理的关键组件。本篇文章将深入探讨这三个概念,并通过`...
在iOS开发中,应用程序的生命周期管理和后台运行能力是至关重要的。本文将深入探讨【标题】"06-应用程序1"中涉及的几个...理解并掌握这些知识点对于iOS开发者来说至关重要,它们是构建功能丰富、高效运行的应用的基础。
理解NSRunLoop的工作方式对于处理长时间运行的任务和保持应用响应性非常重要。 10. **UIKit框架**:对于iOS开发,UIKit框架提供了构建用户界面和处理用户交互的所有工具。学习如何使用UIViewController、UIView、...
[[NSRunLoop currentRunLoop]addTimer:_timer forMode:NSDefaultRunLoopMode]; 改为: /*每秒刷新60次的定时器*/ _time = [CADisplayLink displayLinkWithTarget:self selector:@selector(play)]; /*将...
4. **多线程**:GCD(Grand Central Dispatch)、NSOperationQueue、Thread和NSRunLoop的理解与使用,以及异步编程在iOS中的实现。 5. **网络编程**:URLSession的使用,包括GET、POST请求,处理JSON数据,以及网络...
在Thread的NSRunloop中添加进RunLoopSource也是在IOS里面获取常驻线程的一个主要方法手段(开源项目AFNetworking就是用这种手段获取的常驻线程)。从该演示代码我们还可以一窥Objective-C是怎样封装C以提供更加简单...
- NSThread、NSRunLoop的理解及其与GCD的区别。 7. **动画** - Core Animation的理解,如何创建基本的CAAnimation。 - UIView动画的使用,包括transition、animationBlocks等。 - CAPropertyAnimation和...
我们将以"Nsrun loop test"为例,这是一个简单的示例,帮助我们理解消息循环的工作机制。 消息循环是操作系统和应用程序之间进行通信的一种机制。在Windows、macOS和许多其他GUI系统中,应用程序通常通过消息队列...
理解NSRunLoop的工作原理对于优化应用性能和避免阻塞主线程至关重要。 接下来,我们来看NSOperation。NSOperation和NSOperationQueue是Objective-C中的面向对象的并发模型,提供了更高级别的抽象,相比GCD更加灵活...
了解NSArray, NSDictionary, NSString等基本数据结构的用法,以及NSRunLoop, NSNotification等系统服务,是每个开发者必备的技能。 3. **Cocoa和Cocoa Touch**: Cocoa是Mac OS X上的开发框架,Cocoa Touch则是iOS...
首先,`NSTimer`是`NSRunLoop`的一部分,它可以在指定的时间间隔后调用一个方法。创建`NSTimer`的基本步骤如下: 1. **创建计时器**: 使用`+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)interval ...
- 考虑RunLoop模式:理解NSRunLoop的不同模式,如NSDefaultRunLoopMode和UITrackingRunLoopMode,确保计时器在正确的情景下触发。 - 优化性能:例如,对于CADisplayLink,可能探讨了如何调整其frameInterval属性来...
`NSTimer`是`NSRunLoop`的一部分,它不直接运行在主线程上,而是依赖于运行循环(`NSRunLoop`)来安排和触发事件。创建`NSTimer`时,我们需要指定间隔时间、重复次数、以及一个selector(方法名),当定时器触发时,...