`
zjjzmw1
  • 浏览: 1367856 次
  • 性别: Icon_minigender_1
  • 来自: 开封
社区版块
存档分类
最新评论

nsrunLoop 的理解。。。转载的。。。

阅读更多

原文地址:http://www.cnblogs.com/tangbinblog/archive/2012/12/07/2807088.html

 

 

 

iOS RunLoop 初识

 

今天突然才之间才意识到NSTimer这样的运行方式,是在多线程中实现的循环还是在主线程中去实现的呢。当然不可能是在主线程中的while那么简单,那样什么都干不了,简单看了下NSTimer是以同步方式运行的。时间到了,消息发出后,ontimer的函数是在主线程上调用的。

我们会经常看到这样的代码:

  1. - (IBAction)start:(id)sender  
  2. {  
  3. pageStillLoading = YES;  
  4. [NSThread detachNewThreadSelector:@selector(loadPageInBackground:)toTarget:self withObject:nil];  
  5. [progress setHidden:NO];  
  6. while (pageStillLoading) {  
  7. [NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];  
  8. }  
  9. [progress setHidden:YES];  
  10. }  
复制代码

这段代码很神奇的,因为他会“暂停”代码运行,而且程序运行不会因为这里有一个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)

    总的来说,理解和熟练运用CFRunLoop和NSRunLoop对于优化iOS和Mac OS X应用程序的性能至关重要。它们是系统级的事件处理机制,能够有效提升用户体验,减少不必要的CPU占用,并保证应用程序的响应速度。通过深入学习这...

    NSRunLoopDemo

    综上所述,`NSRunLoopDemo`提供了丰富的示例,帮助开发者深入理解`NSRunLoop`的工作原理及其在实际开发中的应用。通过学习这个项目,你可以掌握如何有效地使用`NSRunLoop`来提升应用程序的性能和用户体验。

    LightWeightRunLoop-A-Reactor-Style-NSRunLoop, NSRunLoop反应器样式实现.zip

    LightWeightRunLoop-A-Reactor-Style-NSRunLoop, NSRunLoop反应器样式实现 LightWeightRunLoop在其他线程,定时器,URLConnection,LWStream ( LWInputStream、LWOutputStream ),LWPort ( LWSocketPort ) 等上实现 ...

    RunLoop例子

    Run Loop的配置和管理可以通过Objective-C的CFRunLoopRef(Core Foundation层)和NSRunLoop(Foundation层)进行。开发者可以通过添加源(Sources)、观察者(Observers)和端口(Ports)来定制Run Loop的行为,例如...

    RunLoop示例

    首先,让我们理解`NSThread`。`NSThread`是Objective-C中的线程类,用于实现多线程编程。每个应用程序都有一个主线程,通常用于处理用户界面交互。当创建一个新的`NSThread`实例时,你可以定义一个入口点方法,该...

    ios 事件循环原理-runloop

    在 iOS 开发中,事件循环机制扮演着至关重要的角色,其中 NSRunLoop 是一个核心组件,负责管理和处理事件。本文将深入探讨 NSRunLoop 的工作原理和实现机制。 一、什么是 NSRunLoop? NSRunLoop 是一种高明的消息...

    7.多线程篇1

    NSRunLoop的基本使用:通过`[[NSRunLoop mainRunLoop] runUntilDate:]`或`[[NSRunLoop mainRunLoop] run]`启动运行循环。 - B. NSRunLoop的模式:NSRunLoop有多个运行模式(如NSDefaultRunLoopMode、...

    DispatchSourceTest.zip

    在iOS和macOS开发中,理解并有效使用线程管理技术是至关重要的。`NSThread`、`NSRunLoop`和`Dispatch Queue`是Apple的Foundation框架中用于多线程和异步任务处理的关键组件。本篇文章将深入探讨这三个概念,并通过`...

    06-应用程序1

    在iOS开发中,应用程序的生命周期管理和后台运行能力是至关重要的。本文将深入探讨【标题】"06-应用程序1"中涉及的几个...理解并掌握这些知识点对于iOS开发者来说至关重要,它们是构建功能丰富、高效运行的应用的基础。

    Addison.Wesley.Learning.ObjectiveC.2.0.Jul.2010.rar

    理解NSRunLoop的工作方式对于处理长时间运行的任务和保持应用响应性非常重要。 10. **UIKit框架**:对于iOS开发,UIKit框架提供了构建用户界面和处理用户交互的所有工具。学习如何使用UIViewController、UIView、...

    ios-打地鼠 小游戏.zip

    [[NSRunLoop currentRunLoop]addTimer:_timer forMode:NSDefaultRunLoopMode]; 改为: /*每秒刷新60次的定时器*/ _time = [CADisplayLink displayLinkWithTarget:self selector:@selector(play)]; /*将...

    ios笔试题库

    4. **多线程**:GCD(Grand Central Dispatch)、NSOperationQueue、Thread和NSRunLoop的理解与使用,以及异步编程在iOS中的实现。 5. **网络编程**:URLSession的使用,包括GET、POST请求,处理JSON数据,以及网络...

    TestRunLoopDemo

    在Thread的NSRunloop中添加进RunLoopSource也是在IOS里面获取常驻线程的一个主要方法手段(开源项目AFNetworking就是用这种手段获取的常驻线程)。从该演示代码我们还可以一窥Objective-C是怎样封装C以提供更加简单...

    IOS面试题总结,集合了很多培训机构的老师精心整理出来的,绝对给力

    - NSThread、NSRunLoop的理解及其与GCD的区别。 7. **动画** - Core Animation的理解,如何创建基本的CAAnimation。 - UIView动画的使用,包括transition、animationBlocks等。 - CAPropertyAnimation和...

    Nsrun loop test

    我们将以"Nsrun loop test"为例,这是一个简单的示例,帮助我们理解消息循环的工作机制。 消息循环是操作系统和应用程序之间进行通信的一种机制。在Windows、macOS和许多其他GUI系统中,应用程序通常通过消息队列...

    ConcurrentCource

    理解NSRunLoop的工作原理对于优化应用性能和避免阻塞主线程至关重要。 接下来,我们来看NSOperation。NSOperation和NSOperationQueue是Objective-C中的面向对象的并发模型,提供了更高级别的抽象,相比GCD更加灵活...

    Objective.C.for.Absolute.Beginners

    了解NSArray, NSDictionary, NSString等基本数据结构的用法,以及NSRunLoop, NSNotification等系统服务,是每个开发者必备的技能。 3. **Cocoa和Cocoa Touch**: Cocoa是Mac OS X上的开发框架,Cocoa Touch则是iOS...

    iOS计时器(OC版)

    首先,`NSTimer`是`NSRunLoop`的一部分,它可以在指定的时间间隔后调用一个方法。创建`NSTimer`的基本步骤如下: 1. **创建计时器**: 使用`+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)interval ...

    TimerAnalysis.zip

    - 考虑RunLoop模式:理解NSRunLoop的不同模式,如NSDefaultRunLoopMode和UITrackingRunLoopMode,确保计时器在正确的情景下触发。 - 优化性能:例如,对于CADisplayLink,可能探讨了如何调整其frameInterval属性来...

    简单的时间选择器Nstimer

    `NSTimer`是`NSRunLoop`的一部分,它不直接运行在主线程上,而是依赖于运行循环(`NSRunLoop`)来安排和触发事件。创建`NSTimer`时,我们需要指定间隔时间、重复次数、以及一个selector(方法名),当定时器触发时,...

Global site tag (gtag.js) - Google Analytics