NSRunloop 个人理解

参考来源   http://www.dreamingwish.com/article/ios-multithread-program-runloop-the.html

RunLoop是一个事件循环的消息处理机制(一个圈不停的转,等着”人"来给他发配任务);

RunLoop就是一个循环,用来不停的调度工作以及处理输入事件。开启一个新的线程就是为了在这个新的线程中处理事件,但是线程一直开启的话会消耗资源,使用Runloop的目的就是当线程需要工作的时候工作,不需要工作的时候处于休眠状态;但是RunLoop不是自动启动的,它需要在你的线程代码在一个合适的时候启动RunLoop并正确的响应事件。每个线程包括主线程都有自己的RunLoop object,但是只有辅助线程才需要显示的运行他的RunLoop,而主线程会在程序启动的时候自动创建并运行它的RunLoop。

RunLoop是一个循环,你的线程进入并使用它来运行响应输入事件和事件处理程序,但是你的代码需要提供实现循环的部分语句,其实就是while和for循环来运行RunLoop。在循环中,Run Loop object来运行事件处理代码,它响应接收到的事件,并启动已安装的处理程序。

NSRunloop接收的两种源是input source/timer source;

 RunLoop的概念结构以及两种源。输入源传递异步消息给响应的处理程序,调用runUntilData:方法退出;

Input Sources

As described in Apple‘s Run Loops programming guide, a run loop contains two types of sources: inputs and timers. An input source is basically some kind of external signal from outside the runloop itself.

除了处理输入源,run loops也会生成关于run loop行为的通知(notifications)。     注册runloop观察者observer可以手打这些通知,并在线程上使用他们做额外处理。

它有一个基本的作用就是管理autorelease pool,autorelease pool中的对象什么时候释放,不用开发者考虑,因为runloop会一直循环检查执行;

Runloop并不是一种并发机制,因为它不并行执行任务。不过在主操作队列中,Runloop直接配合着任务的执行,它提供了让代码异步执行的一种机制。

Runloop比起操作队列或者GCD来说,更加容易使用,因为通过runloop,开发者不必处理并发中的复杂状况,就能异步能执行任务;

一个runloop总是绑定在特定的线程中。main runloop是与主线程相关的,在每一个cocoa或者cocoaTouch程序中,这个main runloop祈祷核心作用--他负责处理UI事件,计时器,以及其他内核相关事件;无论什么时候调用计时器,NSURLConnection,或者调用performseletor:with object:after delay;runloop都将在后台发挥重要作用;

  • RunLoop 模式

Run Loop 的模式是所有要监视的输入源,定时源和要通知的RunLoop注册观察者的集合。每次运行RunLoop都要设置它的运行模式。在RunLoop运行过程中,只有模式相关的源才会被监视并允许他们传递事件消息。

通常在代码中,模式都是被自己指定的。Cocoa和Core Foundation定义了一个默认的和一些常用的模式,在你的代码中都是用字符串来指定这些模式。你必须添加一个或多个输入源,定时源或者观察者才能让你的RunLoop有意义。

通过指定模式还可以使RunLoop在某一阶段过滤来源于源的事件。大多数时候,RunLoop都是运行在系统默认的模式之下。但是模态模板(modal panle)运行在”modal”模式下。在这种模式下,只有和模式面板相关的源才可以和线程传递消息。

 模式的区分,基于事件的源而不是事件的种类。例如,你不可以使用模式只选择鼠标或键盘按下的事件。事件的源取决于输入源的种类:基于端口的源或者自定义的源;

表中列出的是Cocoa和Core Foundation定义的标准模式,并且介绍何时使用他们。


Mode


Name


Description


Default


NSDefaultRunLoopMode(Cocoa)

kCFRunLoopDefaultMode (Core Foundation)


The default mode is the one used for most operations. Most of the time, you should use this mode to start your run loop and configure your input sources.


Connection


NSConnectionReplyMode(Cocoa)


Cocoa uses this mode in conjunction with NSConnection objects to monitor replies. You should rarely need to use this mode yourself.


Modal


NSModalPanelRunLoopMode(Cocoa)


Cocoa uses this mode to identify events intended for modal panels.


Event tracking


NSEventTrackingRunLoopMode(Cocoa)


Cocoa uses this mode to restrict incoming events during mouse-dragging loops and other sorts of user interface tracking loops.


Common modes


NSRunLoopCommonModes(Cocoa)

kCFRunLoopCommonModes (Core Foundation)

This is a configurable group of commonly used modes. Associating an input source with this mode also associates it with each of the modes in the group. For Cocoa applications, this set includes the default, modal, and event tracking modes by default. Core Foundation includes just the default mode initially. You can add custom modes to the set using the CFRunLoopAddCommonMode function.

  • 输入源

输入源异步发送消息给你的线程。事件的来源取决于输入源的种类:基于端口的输入源和自定义的输入源。基于端口的输入源监听程序相应的端口。自定义的输入源监听自定义的事件源。至于Runloop则不关心事件的来源,事件都是由系统传过来的。两类输入源的区别在于如何显示:基于端口的输入源由系统生成,自定义的输入源由自己从其他线程传入;

当自己创建输入源,我们需要将其分配给Runloop的某一个模式下。模式只会在自己的事件才影响监听的源。大多数情况下,run loop运行在默认模式下,但是也可以设置使其运行在特定的模式下 [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode(可以修改) beforeDate: ]]。当一个消息在当前的模式下不能被响应,那就是属于其他的源。

      基于端口的输入源

Cocoa和Core Foundation内置支持使用端口相关的对象和函数来创建的基于端口的源。例如,在Cocoa里面你从来不需要直接创建输入源。你只要简单的创建端口对象,并使用 NSPort的方法把该端口添加到run loop。端口对象会自己处理创建和配置输入源。

在Core Foundation,你必须人工创建端口和它的run loop源。在两种情况下,你都可以使用端口相关的函数(CFMachPortRef,CFMessagePortRef,CFSocketRef)来创建合适的对象。

自定义输入源

为了创建自定义输入源,必须使用Core Foundation里面的CFRunLoopSourceRef类型相关的函数来创建。你可以使用回调函数来配置自定义输入源。Core Fundation会在配置源的不同地方调用回调函数,处理输入事件,在源从run loop移除的时候清理它。

除了定义在事件到达时自定义输入源的行为,你也必须定义消息传递机制。源的这部分运行在单独的线程里面,并负责在数据等待处理的时候传递数据给源并通知它处理数据。消息传递机制的定义取决于你,但最好不要过于复杂。

Cocoa 执行selector 源

除了基于端口的源,Cocoa也可以自定义输入源,允许你在任何线程执行selector。和基于端口的源一样,执行selector的源也会在目标线程上序列化,以减少在同一个线程多个方法执行时可能会出现的同步问题。不过selector的源执行完毕后会自动从runloop移除。

当你要执行的selector在其他线程执行时,其他线程必须有一个活动的runloop,比如performSelectorOnMainThread:withObject:waitUntilDone: 主线程的runloop是一定执行的。但是如果要在自己创建的线程上执行,必须显示的启动runloop,在没有启动runloop之前线程处于等待状态。

下面是NSObject中可在其他线程执行的selector。


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 an NSThreadobject. 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 theperformSelector:withObject:afterDelay:orperformSelector:withObject:afterDelay:inModes:method.

  • 何时使用 RunLoop

仅当在为你的程序创建辅助线程的时候才需要显式的运行一个RunLoop(就是开启一个新的线程的时候)。程序在启动的时候就由Cocoa和carbon开启了一个主线程,同时 开启了主RunLoop循环。

RunLoop在你和线程需要交互的时候才开启,比如:

    1. 使用端口或输入源来和其他线程通讯
    2. 使用线程定时器
    3. Cocoa中使用performSelector...的方法
    4. 使线程周期性工作
  • 使用 Run Loop 对象

Run Loop 对象提供了添加输入源、定时器和观察者以及启动RunLoop的方法。每一个线程都有唯一与之相关的RunLoop对象。在Carbon或BSD中提供的是CFRunloopRef类型的指针。

          获取RunLoop对象 

    • 在Cocoa中使用NSRunloop对象的currentRunloop方法获取NSRunloop对象
    • 使用CFRunloopGetCurrent函数

虽然他俩的类型不同,但是可以再NSRunloop中获取CF的对象,它里面有一个getCFRunLoop方法;两者都指向同一个runloop。

  • 配置 Run Loop

在你们辅助线程运行Run Loop 之前,你必须添加一个输入源或者定时器给他,否则他就自动退出了。

除了添加源,你也可以添加一个观察者对Run Loop 的执行阶段进行观察。

当一个长时间运行的线程添加Run Loop的时候,最好添加一个输入源到Run Loop用来接受消息。虽然可以使用辅助定时器来进入Run Loop,但是一旦定时器触发后,Run Loop就退出了。虽然添加一个循环定时器可是保持长久的运行,但是这也会导致周期性的唤醒线程,这也是轮训的另一种形式。所以最好的是添加爱一个输入源,在输入源发生之前,他一直处于休眠状态。

  • 启动 Run Loop

启动Run Loop只对程序的辅助线程有用,启动后必须添加一个输入源或者一个定时器,否则Run Loop自动退出。

有三种方式启动Run Loop:无条件的、设置超时时间、设置特定模式;

无条件的是最容易的启动Run Loop的方法,但也是最不好的,因为你对Run Loop的控制最少,你可以添加输入源和定时器,但是你退出它的唯一方法就是杀死它。没有任何办法让这Run Loop运行在自定义模式下。

替代无条件最好的方法就是设置超时时间,这样的话Run Loop可以再某一事件到达,或者规定时间已到的情况下关闭Run Loop。然后重启继续使用。

还可以使用特定模式,它与时间超时不互斥,但是它可以设置自己Run Loop所关心的模式,限制了传递给Run Loop的事件源的类型。

时间: 2024-11-09 02:29:28

NSRunloop 个人理解的相关文章

关于NSRunLoop深入理解和NSTimer的结合使用

一.什么是NSRunLoop NSRunLoop是消息机制的处理模式 NSRunLoop的作用在于有事情做的时候使的当前NSRunLoop的线程工作,没有事情做让当前NSRunLoop的线程休眠 NSTimer默认添加到当前NSRunLoop中,也可以手动制定添加到自己新建的NSRunLoop NSRunLoop就是一直在循环检测,从线程start到线程end,检测inputsource(如点击,双击等操作)同步事件,检测timesource同步事件,检测到输入源会执行处理函数,首先会产生通知,

NSRunLoop的利用

一.NSRunLoop的理解 在初学C语言编程的时候,经常会写一种控制台中的程序,程序启动黑色的输入框,等待用户的输入,输入一组数据之后程序继续往下执行程序在等待用户输入数据时会阻塞,这是一种最简单的单线程程序执行的模式.这种简单的编程模型在实际的应用中很难满足用户的需要,比如ios中的app的主线程需要同时响应多种消息,用户触摸事件.timer定时器到时.其它线程发送过来的消息,很自然可以想到为了都能处理到这些消息,那么就在一个while循环中,循环遍历处理这些不同是事件(source),这就

NSRunLoop的进一步理解

iPhone应用开发中关于NSRunLoop的概述是本文要介绍的内容,NSRunLoop是一种更加高明的消息处理模式,他就高明在对消息处理过程进行了更好的抽象和封装,这样才能是的你不用处理一些很琐碎很低层次的具体消息的处理,在NSRunLoop中每一个消息就被打包在input source或者是timer source中了,来看详细内容. 1.什么是NSRunLoop 我们会经常看到这样的代码: - (IBAction)start:(id)sender { pageStillLoading =

关于 NSTimer 和 NSRunLoop 的一些理解

一:NSTimer和NSRunLoop的关系? 只要出现NSTimer必须要有NSRunLoop,NSTimer必须依赖NSRunLoop才能执行 .NSTimer其实也是一种资源,如果看过多线程编程指引文档的话,我们会发现所有的source如果要起作用,就得加到runloop中去.同理timer这种资源要想起作用,那肯定也需要加到runloop中才会生效喽.如果一个runloop里面不包含任何资源的话,运行该runloop时会立马退出.你可能会说那我们APP的主线程的runloop我们没有往其

关于NSRunLoop和NSTimer的深入理解

一.什么是NSRunLoop NSRunLoop是消息机制的处理模式 NSRunLoop的作用在于有事情做的时候使的当前NSRunLoop的线程工作,没有事情做让当前NSRunLoop的线程休眠 NSTimer默认添加到当前NSRunLoop中,也可以手动制定添加到自己新建的NSRunLoop NSRunLoop就是一直在循环检测,从线程start到线程end,检测inputsource(如点击,双击等操作)同步事件,检测timesource同步事件,检测到输入源会执行处理函数,首先会产生通知,

深入理解Runloop,看我一篇就够了

前言 RunLoop 是 iOS 和 OSX 开发中非常基础的一个概念,为了让大家更加快速融入,请先一段代码: + (NSThread *)networkRequestThread { static NSThread *_networkRequestThread = nil; static dispatch_once_t oncePredicate; dispatch_once(&oncePredicate, ^{ _networkRequestThread = [[NSThread alloc

iOS开发中NSRunloop跟NSTimer的问题

在Windows时代,大家肯定对SendMessage,PostMessage,GetMessage有所了解,这些都是windows中的消 息处理函数,那对应在ios中是什么呢,其实就是NSRunloop这个东西.在ios中,所有消息都会被添加到NSRunloop中,分为'input source'跟'timer source'种,并在循环中检查是不是有事件需要发生,如果需要那么就调用相应的函数处理. 我们在使用NSTimer的时候,可能会接触到runloop的概念, 下面是一个简单的例子 -

[iOS]浅谈NSRunloop工作原理和相关应用

一. 认识NSRunloop  1.1 NSRunloop与程序运行 那么具体什么是NSRunLoop呢?其实NSRunLoop的本质是一个消息机制的处理模式.让我们首先来看一下程序的入口——main.m文件,一个ios程序启动后,只有短短的十行代码居然能保持整个应用程序一直运行而没有退出,是不是有点意思?程序之所以没有直接退出是因为UIApplicationMain这个函数内部默认启动了一个跟主线程相关的NSRunloop对象,而UIApplicationMain这个函数一直执行没有返回就保存

ios:NSRunLoop

ios:NSRunLoop 1.NSRunLoop是消息机制的处理模式 NSRunLoop的作用在于有事情做的时候使的当前NSRunLoop的线程工作,没有事情做让当前NSRunLoop的线程休眠 2.nstimer默认添加到当前NSRunLoop中,也可以手动制定添加到自己新建的NSRunLoop的中 [NSTimer schduledTimerWithTimeInterval: target:selector:userInfo:repeats]; 此方法默认添加到当前NSRunLoop中 N