RunLoop学习笔记澳门新葡京平台游戏

作者:澳门新葡京平台游戏

什么是RunLoop?从字面意思看叫做运行循环,俗称“跑圈”。

  • 什么是RunLoop

    • 运行循环
    • 基本作用:
      • 保持程序的持续运行,如果没有RunLoop,程序执行完main函数就结束了。
      • 处理App中的各种事件(比如触摸事件、定时器事件、Selector事件)
      • 节省CPU资源,提高程序性能:该做事时做事,该休息时休息
      • ......
  • main函数中的RunLoop

    • 在UIApplicationMain函数内部就启动了一个RunLoop,所以UIApplicationMain函数一直没有返回,保持了程序的持续运行
    • 这个默认启动的RunLoop是跟主线程相关联的

1.什么是RunLoop?

  • 从字面意思来看,runloop就是一个运行循环,不断的在跑圈。

RunLoop的主要作用:1、保持程序的持续运行2、处理APP中的各种事件(触摸事件,定时器事件,selector事件)3、节省CPU资源,提高程序性能:有事做事,没事休息

2.RunLoop的作用?

  • RunLoop的基本作用:保持程序的持续运行。
  • 处理App中的各种事件(触摸、定时器、Selector等)。
  • 节省cpu资源,提高程序性能。该做事的时候做事,该休息的时候休息。

main函数中的RunLoop:

#import <UIKit/UIKit.h>#import "AppDelegate.h"int main(int argc, char * argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); }}

3有和没有RunLoop会怎么样?

如果没有RunLoop:

  • 每条线程都有唯一的一个与之对应的RunLoop对象
  • 主线程的RunLoop已经自动创建好了,子线程的RunLoop需要主动创建
  • RunLoop在第一次获取时创建,在线程结束时销毁

有RunLoop

  • 原来在main.m的函数是这样的,UIApplicationMain函数内部就启动了一个RunLoop,所以UIApplicationMain函数一直没有返回,保持了程序的持续运行
  • 这个默认启动的RunLoop是跟主线程相关联的
  • 有RunLoop的情况下,由于main函数里面启动了个RunLoop,所以程序并不会马上退出,保持持续运行状态
int main(int argc, char * argv[]) {
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

澳门新葡京平台游戏 1屏幕快照 2016-10-05 下午10.40.43.png

获得RunLoop对象

没有RunLoop

  • 如果去掉Runloop,那么在main.m中的主函数相当于变成了:
int main(int argc, char * argv[]) {
    NSLog(@"execute main function");
    return 0;
}
  • 以上程序往下走了以后,第3行后程序就结束了;

没有RunLoop,程序执行第三行后就结束了;

  • iOS中有2套API来访问和使用RunLoop

    • 1.Foundation : NSRunLoop
    • 2.CoreFoundation : CFRunLoopRef
    • NSRunLoop和CFRunLoopRef都代表着RunLoop对象
  • Foundation

4.RunLoop对象

  • iOS中有2套API来访问和使用RunLoop
    Foundation
    NSRunLoop

    Core Foundation
    CFRunLoopRef

  • NSRunLoop和CFRunLoopRef都代表着RunLoop对象

  • NSRunLoop是基于CFRunLoopRef的一层OC包装,所以要了解RunLoop内部结构,需要多研究CFRunLoopRef层面的API(Core Foundation层面)

如果有RunLoop:

5.关于RunLoop的一些资料

  • 苹果官方文档

  • CFRunLoopRef

澳门新葡京平台游戏 2屏幕快照 2016-10-05 下午10.46.53.png

[NSRunLoop currentRunLoop];// 获得当前线程的RunLoop对象[NSRunLoop mainRunLoop];// 获得主线程的RunLoop对象

6.RunLoop与线程

  • 每条线程都有唯一的一个与之对应的RunLoop对象

  • 主线程的RunLoop已经自动创建好了,子线程的RunLoop需要主动创建

  • RunLoop在第一次获取时创建,在线程结束时销毁

RunLoop内部其实就是一个do-while循环,在这个循环内部不断的处理各种事件,程序不会执行第7行代码,因此保证了程序不会退出一直运行;

  • CoreFoundation

获得RunLoop对象

  • Foundation
    [NSRunLoop currentRunLoop]; // 获得当前线程的RunLoop对象
    [NSRunLoop mainRunLoop]; // 获得主线程的RunLoop对象

  • Core Foundation
    CFRunLoopGetCurrent(); // 获得当前线程的RunLoop对象
    CFRunLoopGetMain(); // 获得主线程的RunLoop对象

澳门新葡京平台游戏 3屏幕快照 2016-10-05 下午10.26.44.png

7.RunLoop相关类

  • Core Foundation中关于RunLoop的5个类
  • CFRunLoopRef
  • CFRunLoopModeRef
  • CFRunLoopSourceRef
  • CFRunLoopTimerRef
  • CFRunLoopObserverRef

UIApplicationMain函数内部自动启动了一个RunLoop,所以UIApplicationMain一直没有返回,保持程序持续运行。这个默认启动的RunLoop是跟主线程相关联的;

CFRunLoopGetCurrent();// 获得当前线程的RunLoop对象CFRunLoopGetMain();// 获得主线程的RunLoop对象

CFRunLoopModeRef

  • CFRunLoopModeRef代表RunLoop的运行模式
  • 一个 RunLoop 包含若干个 Mode,每个Mode又包含若干个Source/Timer/Observer
  • 每次RunLoop启动时,只能指定其中一个 Mode,这个Mode被称作 CurrentMode
  • 如果需要切换Mode,只能退出Loop,再重新指定一个Mode进入
  • 这样做主要是为了分隔开不同组的Source/Timer/Observer,让其互不影响

RunLoop对象:

  • 苹果官方文档

  • CFRunLoopRef是开源的

Run Loop Modes 系统默认注册了5个Mode:
  1. kCFRunLoopDefaultMode:App的默认Mode,通常主线程是在这个Mode下运行

  2. UITrackingRunLoopMode:界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响

  3. UIInitializationRunLoopMode: 在刚启动 App 时第进入的第一个 Mode,启动完成后就不再使用

  4. GSEventReceiveRunLoopMode: 接受系统事件的内部 Mode,通常用不到

  5. kCFRunLoopCommonModes: 这是一个占位用的Mode,不是一种真正的Mode

iOS中有2套API访问和使用RunLoop:Foundation框架下的:NSRunLoopCoreFoundation框架下的:CFRunLoopRef;CFRunLoopRef和NSRunLoop都代表RunLoop对象;NSRunLoop是基于CFRunLoopRef的一层OC包装,所以要了解RunLoop内部结构,需要多研究CFRunLoopRef层的API;可参考苹果官方文档:

CFRunLoopSourceRef

  • CFRunLoopSourceRef是事件源(输入源)

  • 以前的分法
    Port-Based Sources
    Custom Input Sources
    Cocoa Perform Selector Sources

  • 现在的分法
    Source0:非基于Port的
    Source1:基于Port的

RunLoop与线程

  • CoreFoundation中关于RunLoop的5个类
    • CFRunLoopRef
    • CFRunLoopModeRef
    • CFRunLoopSourceRef
    • CFRunLoopTimerRef
    • CFRunLoopObserverRef

CFRunLoopTimerRef

  • CFRunLoopTimerRef是基于时间的触发器

  • 基本上说的就是NSTimer

每条线程都有唯一一个与之对应的RunLoop对象;主线程的RunLoop已经自动创建好了,子线程的RunLoop需要主动去创建;RunLoop在第一次获取时创建,线程销毁时销毁;

澳门新葡京平台游戏 4runLoop相关类.png

CFRunLoopObserverRef

  • CFRunLoopObserverRef是观察者,能够监听RunLoop的状态改变

  • 可以监听的时间点有以下几个

澳门新葡京平台游戏 5

observer.png

获取RunLoop对象Foundation:

CFRunLoopModeRef

8.RunLoop处理逻辑-官方版

澳门新葡京平台游戏 6

RunLoop_official.png

澳门新葡京平台游戏 7

RunLoop_official2.png

[NSRunLoop currentRunLoop];// 获得当前线程的RunLoop对象[NSRunLoop mainRunLoop]; // 获得主线程的RunLoop对象
  • CFRunLoopModeRef代表RunLoop的运行模式

  • 一个 RunLoop包含若干个 Mode,每个Mode又包含若干个Source/Timer/Observer

  • 每次RunLoop启动时,只能指定其中一个 Mode,这个Mode被称作 CurrentMode

  • 如果需要切换Mode,只能退出Loop,再重新指定一个Mode进入

  • 这样做主要是为了分隔开不同组的Source/Timer/Observer,让其互不影响

  • 系统默认注册了5个Mode:

    • NSDefaultRunLoopMode:App的默认Mode,通常主线程是在这个Mode下运行

9.RunLoop处理逻辑-网友整理版

澳门新葡京平台游戏 8

RunLoop_Nets.png

Core Foundation:

10.RunLoop开发中的使用

  • 当实例化一个时钟timer的时候,添加到运行循环中。

    注意:一定需要销毁该时钟 否则会产生循环应用

  • socket开发中 使用RunLoop 能够监听网络端口数据的接受与发送的情况

学习笔记暂时记录到这里 后续继续记录 :)

CFRunLoopGetCurrent();// 获得当前线程的RunLoop对象CFRunLoopGetMain();// 获得主线程的RunLoop对象
  • UITrackingRunLoopMode:界面跟踪 Mode,用于 ScrollView追踪触摸滑动,保证界面滑动时不受其他Mode 影响
  • UIInitializationRunLoopMode: 在刚启动 App 时第进入的第一个 Mode,启动完成后就不再使用
  • GSEventReceiveRunLoopMode: 接受系统事件的内部 Mode,通常用不到
  • NSRunLoopCommonModes: 这是一个占位用的Mode,不是一种真正的Mode

RunLoop相关类CoreFoundation中关于RunLoop的5个类:CFRunLoopRef //RunLoop对象CFRunLoopModeRef //RunLoop运行模式CFRunLoopSourceRef //RunLoop事件源CFRunLoopTimerRef //RunLoop定时器事件CFRunLoopObserverRef //监听RunLoop状态的观察者

CFRunLoopSourceRef

CFRunLoopModeRef

  • CFRunLoopTimerRef是基于时间的触发器
  • CFRunLoopTimerRef基本上说的就是NSTimer,它受RunLoop的Mode影响
  • 注意: GCD的定时器不受RunLoop的Mode影响

澳门新葡京平台游戏 9mode.png

CFRunLoopSourceRef

一个RunLoop包含若干个Mode,每个Mode又包含若干个source、timer、observer;

  • CFRunLoopSourceRef是事件源

  • 按照官方文档,Source的分类

    • Port-BasedSources
    • Custom InputSources
    • Cocoa PerformSelector Sources
  • 按照函数调用栈,Source的分类

    • Source0:非基于Port的, 用于用户主动触发事件
    • Source1:基于Port的,通过内核和其他线程相互发送消息

每次RunLoop启动时,只能指定其中一个Mode,这个Mode称作CurrentMode;

CFRunLoopObserverRef

如果需要切换Mode,只能退出Loop,再重新指定一个Mode进入;这样做是为了分隔开不同组的source、timer、observer,互不影响;具体怎么退出,怎么重新指定Mode,官方文档并未讲述,我们也不得而知;

  • CFRunLoopObserverRef是观察者, 能够监听RunLoop的状态改变

  • 可以监听的时间点有以下几个

系统默认注册了5个Mode:

澳门新葡京平台游戏 10澳门新葡京平台游戏,监听时间点.png

KCFRunLoopDefaultMode:APP的默认Mode,通常主线程在这个Mode下运行;

  • 添加Observer

UITrackingRunLoopMode:界面跟踪Mode,用于scrollView追踪触摸滑动,保证界面滑动不受其他Mode影响;

UIInitializationRunLoopMode:在刚启动APP时进入的第一个Mode,启动完成后就不再使用;

//创建observerCFRunLoopObserverRefobserver = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(),kCFRunLoopAllActivities,YES,0,^(CFRunLoopObserverRefobserver, CFRunLoopActivityactivity) { NSLog(@"----监听到RunLoop状态发生改变---%zd",activity);});//添加观察者:监听RunLoop的状态CFRunLoopAddObserver(CFRunLoopGetCurrent(),observer, kCFRunLoopDefaultMode);//释放ObserverCFRelease;

GSEventReceiveRunLoopMode:接受系统事件的内部Mode,通常用不到;

KCFRunloopCommonModes:这是一个占位用的Mode,不是真正的Mode;表示具有KCFRunloopCommonModes标记的模式;KCFRunloopCommonModes标记的Mode有两种:0 : <CFString 0x109af3a40 [0x108c687b0]>{contents = "UITrackingRunLoopMode"}2 : <CFString 0x108c88b40 [0x108c687b0]>{contents = "kCFRunLoopDefaultMode"}

因此当一个事件是在RunLoop的KCFRunloopCommonModes模式下,RunLoop在KCFRunLoopDefaultMode和UITrackingRunLoopMode模式时都能处理该事件;

CFRunLoopSourceRef事件源的分类从前:1、Port-Based Sources2、Custom Input Sources3、Cocoa Perform Selector Sources

现在:Source0:非基于Port的,用于用户主动触发的事件Source1:基于Port的,通过内核和其他线程相互发送消息

CFRunLoopTimerRefNSTimer,会受到RunLoop的Mode影响GCD的定时器不受RunLoop的Mode影响

//1.创建NSTimerNSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector userInfo:nil repeats:YES];//2.添加到runloop,当runloop的运行模式为NSDefaultRunLoopMode时候,定时器工作[[NSRunLoop currentRunLoop]addTimer:timer forMode:NSDefaultRunLoopMode];

那么timer只在NSDefaultRunLoopMode下工作;同理如果选择UITrackingRunLoopMode,timer只在UITrackingRunLoopMode下工作;选择NSRunLoopCommonModes,timer在UITrackingRunLoopMode和NSDefaultRunLoopMode下都能正常工作;

//0.创建队列dispatch_queue_t queue = dispatch_get_global_queue;//创建一个GCD定时器/* 第一个参数:表明创建的是一个定时器 第四个参数:队列 */dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);self.timer = timer;//2.设置定时器的开始时间,间隔时间,精准度/* 第1个参数:要给哪个定时器设置 第2个参数:开始时间 第3个参数:间隔时间 第4个参数:精准度 一般为0 提高程序的性能 GCD的单位是纳秒 */dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 2.0 * NSEC_PER_SEC, 10 * NSEC_PER_SEC);//3.设置定时器要调用的方法dispatch_source_set_event_handler(timer, ^{ NSLog(@"GCD-timer");});//4.启动 dispatch_resume;

定时器对象需要声明属性或成员变量去接收,否则这段代码执行完,timer会被销毁;

CFRunLoopObserverRef监听的时间点:

澳门新葡京平台游戏 11activity.png

//创建一个监听对象/* 第一个参数:分配存储空间的 第二个参数:要监听的状态 kCFRunLoopAllActivities 所有状态 第三个参数:是否要持续监听 第四个参数:优先级 第五个参数:回调 */ CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) { switch  { case kCFRunLoopEntry: NSLog(@"runloop进入"); break; case kCFRunLoopBeforeTimers: NSLog(@"runloop要去处理timer"); break; case kCFRunLoopBeforeSources: NSLog(@"runloop要去处理Sources"); break; case kCFRunLoopBeforeWaiting: NSLog(@"runloop要睡觉了"); break; case kCFRunLoopAfterWaiting: NSLog(@"runloop醒来啦"); break; case kCFRunLoopExit: NSLog(@"runloop退出"); break; default: break; }});//给runloop添加监听者/* 第一个参数:要监听哪个runloop 第二个参数:监听者 第三个参数:要监听runloop在哪种运行模式下的状态 */CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);[NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:@selector userInfo:nil repeats:YES];CFRelease;

以上内容是我学习过程中查询资料总结出来的,如有疏漏或错误,欢迎批评指正,也欢迎大家一起交流讨论;关于RunLoop的应用,后面有空再继续补充;

本文由新葡京8455发布,转载请注明来源

关键词: