一、RunLoop的定义

当有持续的异步任务需求时,我们会创建一个独立的生命周期可控的线程。RunLoop就是控制线程生命周期并接收事件进行处理的机制。

RunLoop是iOS事件响应与任务处理最核心的机制,它贯穿iOS整个系统。

Foundation: NSRunLoopCore Foundation: CFRunLoop 核心部分,代码开源,C 语言编写,跨平台

二、目的

通过RunLoop机制实现省电,流畅,响应速度快,用户体验好

三、理解

进程是一家工厂,线程是一个流水线,Run Loop就是流水线上的主管;当工厂接到商家的订单分配给这个流水线时,Run Loop就启动这个流水线,让流水线动起来,生产产品;当产品生产完毕时,Run Loop就会暂时停下流水线,节约资源。RunLoop管理流水线,流水线才不会因为无所事事被工厂销毁;而不需要流水线时,就会辞退RunLoop这个 主管,即退出线程,把所有资源释放。

RunLoop并不是iOS平台的专属概念,在任何平台的多线程编程中,为控制线程的生命周期,接收处理异步消息都需要类似RunLoop的循环机制实现,Android的Looper就是类似的机制。

四、特性

  • 主线程的RunLoop在应用启动的时候就会自动创建

  • 其他线程则需要在该线程下自己启动

  • 不能自己创建RunLoop

  • RunLoop并不是线程安全的,所以需要避免在其他线程上调用当前线程的RunLoop

  • RunLoop负责管理autorelease pools

  • RunLoop负责处理消息事件,即输入源事件和计时器事件

RunLoop机制

主线程 (有 RunLoop 的线程) 几乎所有函数都从以下六个之一的函数调起:

  • CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION

    CFRunloop is calling out to an abserver callback function

    用于向外部报告 RunLoop 当前状态的更改,框架中很多机制都由 RunLoopObserver 触发,如 CAAnimation

  • CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK

    CFRunloop is calling out to a block

    消息通知、非延迟的perform、dispatch调用、block回调、KVO

  • CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUECFRunloop is servicing the main desipatch queue

  • CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION

    CFRunloop is calling out to a timer callback function

    延迟的perform, 延迟dispatch调用

  • CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION

    CFRunloop is calling out to a source 0 perform function

    处理App内部事件、App自己负责管理(触发),如UIEvent、CFSocket。普通函数调用,系统调用

  • CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION

    CFRunloop is calling out to a source 1 perform function

    由RunLoop和内核管理,Mach port驱动,如CFMachPort、CFMessagePort

runloop框架:

RunLoop 运行时:

runloop主要有以下六种状态:

  • kCFRunLoopEntry -- 进入runloop循环

  • kCFRunLoopBeforeTimers -- 处理定时调用前回调

  • kCFRunLoopBeforeSources -- 处理input sources的事件

  • kCFRunLoopBeforeWaiting -- runloop睡眠前调用

  • kCFRunLoopAfterWaiting -- runloop唤醒后调用

  • kCFRunLoopExit -- 退出runloop

RunLoop 运行时调用栈

主线程App运行时

RunLoopObserver与Autorelease Pool的关系

UIKit 通过 RunLoopObserver 在 RunLoop 两次 Sleep 间对 Autorelease Pool 进行 Pop 和 Push 将这次 Loop 中产生的 Autorelease 对象释放

RunLoop的挂起与唤醒:

指定用于唤醒的mach_port端口

调用mach_msg监听唤醒端口,被唤醒前系统内核将这个线程挂起,停留在mach_msg_trap状态。

由另一个线程向内核发送这个端口的msg后,trap状态被唤醒,RunLoop继续工作。

RunLoop支持的消息事件(Events)

  • RunLoop

    • 支持接收处理输入源(Input Source)事件,包括:

      系统的Mach Port事件,是一种通讯事件自定义输入事件

    • 支持接受处理定时源(Timer)事件

    • 在启动RunLoop之前,必须添加监听的输入源事件或者定时源事件,否则调用[runloop run]会直接返回,而不会进入循环让线程长驻。

      如果没有添加任何输入源事件或Timer事件,线程会一直在无限循环空转中,会一直占用CPU时间片,没有实现资源的合理分配。没有while循环且没有添加任何输入源或Timer的线程,线程会直接完成,被系统回收。

 //错误做法
NSRunLoop *runLoop=[NSRunLoop currentRunLoop];
while(!self.isCancelled && !self.isFinished){
[runLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:]];
};
//正确做法
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
while(!self.isCancelled && !self.isFinished){
@autoreleasepool{
[runLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:]];
}
}

Run Loop Modes

  • 理解Run Loop Mode就是流水线上支持生产的产品类型,流水线在一个时刻只能在一种模式下运行,生产某一类型的产品。消息事件就是订单。

  • Cocoa定义了四中Mode

    Default:NSDefaultRunLoopMode,默认模式,在Run Loop没有指定Mode的时候,默认就跑在Default Mode下

    Connection:NSConnectionReplyMode,用来监听处理网络请求NSConnection的事件

    Modal:NSModalPanelRunLoopMode,OS X的Modal面板事件

    Event tracking:UITrackingRunLoopMode,拖动事件

    Common mode:NSRunLoopCommonModes,是一个模式集合,当绑定一个事件源到这个模式集合的时候就相当于绑定到了集合内的每一个模式

  • RunLoop可以通过 [acceptInputForMode:beforeDate:]和[runMode:beforeDate:]来指定在一段时间内的运行模式。如果不 指定的话,RunLoop默认会运行在Default下(不断重复调用runMode:NSDefaultRunLoopMode beforDate:)

  • 在主线程启动一个计时器Timer,然后拖动UITableView或者 UIScrollView,计时器不执行。这是因为,为了更好的用户体验,在主线程中Event tracking模式的优先级最高。在用户拖动控件时,主线程的Run Loop是运行在Event tracking Mode下,而创建的Timer是默认关联为Default Mode,因此系统不会立即执行Default Mode下接收的事件。解决方法:

 NSTimer*timer=[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerFireMethod:)userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop]addTimer:timer forMode:NSRunLoopCommonModes];
//或
[[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];
[timer fire];

Run Loop应用实践

Run Loop主要有以下三个应用场景:

  • 维护线程的生命周期,让线程不自动退出,isFinished为Yes时退出。

 NSRunLoop*runLoop=[NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
while(!self.isCancelled&&!self.isFinished){
@autoreleasepool{
[runLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:]]; }
}
  • 创建常驻线程,执行一些会一直存在的任务。该线程的生命周期跟App相同
@autoreleasepool{
NSRunLoop *runLoop=[NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode: NSDefaultRunLoopMode];
[runLoop run];
}
  • 在一定时间内监听某种事件,或执行某种任务的线程, 如下代码,在30分钟内,每隔30s执行onTimerFired:。这种场景一般会出现在,如我需要在应用启动之后,在一定时间内持续更新某项数据。
@autoreleasepool{
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
NSTimer *udpateTimer = [NSTimer timerWithTimeInterval: target:self selector:@selector(onTimerFired:)userInfo:nil repeats:YES];
[runLoop addTimer:udpateTimer forMode:NSRunLoopCommonModes];
[runLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:*]];
}

AFNetworking中RunLoop的创建:

+(void)networkRequestThreadEntryPoint:(id)__unusedobject{
@autoreleasepool{
[[NSThread currentThread] setName:@"AFNetworking"];
//这里主要是监听某个port,目的是让这个Thread不会回收
//[runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
NSRunLoop *runLoop=[NSRunLoop currentRunLoop];
[runLoop run];
}
}
+(NSThread*)networkRequestThread{
static NSThread *_networkRequestThread = nil;
static dispatch_once_toncePredicate;
dispatch_once(&oncePredicate,^{
_networkRequestThread = [[NSThread alloc] initWithTarget:self selector:@selector(networkRequestThreadEntryPoint:)object:nil];
[_networkRequestThread start];
});
return _networkRequestThread;
}

iOS Runloop理解的更多相关文章

  1. iOS runLoop 理解

    目录 概述 run loop modes 一.概述 run loop叫事件处理循环,就是循环地接受各种各样的事件.run loop是oc用来管理线程里异步事件的工具.一个线程通过run loop可以监 ...

  2. iOS --runtime理解

    iOS~runtime理解 Runtime是想要做好iOS开发,或者说是真正的深刻的掌握OC这门语言所必需理解的东西.最近在学习Runtime,有自己的一些心得,整理如下,一为 查阅方便二为 或许能给 ...

  3. iOS 深入理解RunLoop

    RunLoop 是 iOS 和 OSX 开发中非常基础的一个概念,这篇文章将从 CFRunLoop 的源码入手,介绍 RunLoop 的概念以及底层实现原理.之后会介绍一下在 iOS 中,苹果是如何利 ...

  4. ios -RunLoop(简单理解)

    一. RunLoop简介 RunLoop字面意思是运行时,即跑圈得意思.它可以在我们需要的时候自己跑起来运行,在我们没有操作的时候就停下来休息,充分节省CPU资源,提高程序性能. 二. RunLoop ...

  5. iOS开发 - RunLoop理解

    RunLoop概念 运行循环,一个 run loop 就是一个事件处理的循环,用来不停的调度工作以及处理事件 作用 保持程序的持续运行 监听处理App中的各种事件(触摸事件,定时器事件,selecto ...

  6. iOS runloop 资源汇总-b

    RunLoop 是 iOS 和 OSX 开发中非常基础的一个概念,这篇文章将从 CFRunLoop 的源码入手,介绍 RunLoop 的概念以及底层实现原理.之后会介绍一下在 iOS 中,苹果是如何利 ...

  7. iOS RunLoop详解

    1. RunLoop简介 1.1 什么是RUnLoop 可以理解为字面的意思:Run表示运行,Loop表示循环.结合在一起就是运行的循环.通常叫做运行循环. RunLoop实际上是一个对象,这个对象在 ...

  8. iOS Runloop 消息循环

    介绍 Runloop是一种事件监听循环,可以理解成一个while死循环,监听到事件就起来,没有就休息. Runloop可以在不同模式下进行切换,iOS有五种模式,其中UIInitializationR ...

  9. ios runloop学习

    今天突然才之间才意识到NSTimer这样的运行方式,是在多线程中实现的循环还是在主线程中去实现的呢.当然不可能是在主线程中的while那么简单,那样什么都干不了,简单看了下NSTimer是以同步方式运 ...

随机推荐

  1. Vue仿抽屉

    创建VUE项目的步骤: npm install vue-cli -g vue init webpack myproject cd myproject npm run dev 组件:它是可扩展的html ...

  2. APC | Memcache等缓存key冲突的解决的方法

    版权声明:https://github.com/wusuopubupt https://blog.csdn.net/wusuopuBUPT/article/details/24397109 apc.m ...

  3. CF1045G:AI robots(CDQ分治)

    Description 火星上有$n$个机器人排成一行,第$i$个机器人的位置为$x_i$,视野为$r_i​$,智商为$q_i​$.我们认为第$i$个机器人可以看到的位置是$[x_i−r_i,x_i+ ...

  4. [题目] Luogu P3707 [SDOI2017]相关分析

    参考资料:[Luogu 3707] SDOI2017 相关分析 P3707 [SDOI2017]相关分析 TFRAC FRAC DFRAC \(\tfrac{\sum}{1}\) \(\frac{\s ...

  5. Pollard_Rho大数分解模板题 pku-2191

    题意:给你一个数n,  定义m=2k-1,   {k|1<=k<=n},并且 k为素数;  当m为合数时,求分解为质因数,输出格式如下:47 * 178481 = 8388607 = ( ...

  6. Java中static、final、static final的区别【转】

    说明:不一定准确,但是最快理解. final: final可以修饰:属性,方法,类,局部变量(方法中的变量) final修饰的属性的初始化可以在编译期,也可以在运行期,初始化后不能被改变. final ...

  7. bwdist matlab

    bwdist函数用于计算元素之间的距离. 举个例子: 如果a= 0     0     0     0     0     0     1     1     1     0     0     1  ...

  8. POST提交数据之---Content-Type的理解;

    POST提交数据之---Content-Type的理解: Content-Type是指http/https发送信息至服务器时的内容编码类型,contentType用于表明发送数据流的类型,服务器根据编 ...

  9. Objective-C 浅拷贝与深拷贝

    一个Objective-C对象通常分配在堆上,并有一个或者多个指针指向它.如下代码及其关系图所示: NSObject *obj1 = [[NSObject alloc] init]; NSObject ...

  10. node.js 基础二 开启服务器监听

    1.server.js 2.监听 一 server.js 二 监听 运行server.js后,浏览器打开:http://localhost:8888/ //====================== ...