iOS 中Runloop

Runloop 字面理解为运行循环

作用:
1,保持程序的持续运行。
2,处理程序中的各种事件,比如触摸事件,定时器事件。Selector方法。
3,节省CPU资源,提高程序性能。该做事时做事,该休息时休息(Runloop的状态)

iOS中有两套API访问Runloop
1,Foundation框架
NSRunloop
2,Core Foundation框架
CFRunloopRef

NSRunloop是基于CFRunloopRef的封装

一,runloop与线程的关系
1,每条线程都有唯一的一个与之对应的runloop
2,主线程的runloop已经自动创建好了,子线程的runloop需要主动创建。
3,runloop在第一次获取时创建,在线程结束时销毁。

二,CFRunloopModeRef
CFRunloopModeRef代表Runloop的运行模式
1,一个Runloop包含多个运行模式Mode,每个Mode又包含若干个Source/Timer/Observer。
2,每次Runloop启动时只能启动一个mode,称之为currentmode,可通过此方法获取。
3,如果要切换mode,只能先退出loop,再重新指定一个Mode进入。

系统默认为我们注册了5种运行模式,这里只介绍公开暴露出来的两种

NSDefaultRunLoopMode 默认Mode,通常主线程运行模式。
NSEventTrackingRunLoopMode 界面跟踪Mode,ScrollView追踪滑动触摸,保证界面滑动时不受其他Mode影响。
NSRunLoopCommonModes 标签,被标记的对象可以运行在被标签标记的模式下,随着模式的切换而切换,比如NSTimer。

iOS 中公开暴露出来的只有 NSDefaultRunLoopMode 和 NSRunLoopCommonModes。 NSRunLoopCommonModes 实际上是一个 Mode 的集合,默认包括 NSDefaultRunLoopMode 和 NSEventTrackingRunLoopMode(注意:并不是说Runloop会运行在kCFRunLoopCommonModes这种模式下,而是相当于分别注册了 NSDefaultRunLoopMode和 UITrackingRunLoopMode。当然你也可以通过调用CFRunLoopAddCommonMode()方法将自定义Mode放到 kCFRunLoopCommonModes组合)。

三,CFRunLoopSourceRef
以前分类:
1,Port
2,Custom,Input Source
3,performselector
现在:
1,Source0:
非基于port的,用户主动触发的,如触摸等
2,Source1:
基于Port的,基于内核和其他线程相互发送消息。

四,CFRunLoopObserverRef
CFRunLoopObserver是观察者,可以观察RunLoop的各种状态,并抛出回调。

struct __CFRunLoopObserver {
    CFRuntimeBase _base;
    pthread_mutex_t _lock;
    CFRunLoopRef _runLoop;
    CFIndex _rlCount;
    CFOptionFlags _activities;      /* immutable */
    CFIndex _order;         /* immutable */
    CFRunLoopObserverCallBack _callout; /* immutable */
    CFRunLoopObserverContext _context;  /* immutable, except invalidation */
};

CFRunLoopObserver可以观察的状态有如下6种:

/* Run Loop Observer Activities */
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
    kCFRunLoopEntry = (1UL << 0), //即将进入run loop
    kCFRunLoopBeforeTimers = (1UL << 1), //即将处理timer
    kCFRunLoopBeforeSources = (1UL << 2),//即将处理source
    kCFRunLoopBeforeWaiting = (1UL << 5),//即将进入休眠
    kCFRunLoopAfterWaiting = (1UL << 6),//被唤醒但是还没开始处理事件
    kCFRunLoopExit = (1UL << 7),//run loop已经退出
    kCFRunLoopAllActivities = 0x0FFFFFFFU
};
什么是Runloop?

字面意思是一个运行循环,其实内部是一个do while 循环,在处理各种事件,timer,source,Observer。
一个线程对应一个Runloop。主线程自动启动,子线程需要手动启动,调用Run方法。
Runloop只能选择一个模式启动,更改模式需要先退出再进入新模式。如果Model没有任何timer。source,那么直接退出runloop。

自动释放池什么时候释放?

根据Observer观察的Runloop状态释放,runloop退出。

五,Runloop应用
1,NSTimer
定时器设置为CommonMode更精准
2,ImageVIew显示
将图片的显示设置在UITracking模式,可以保证在列表滑动的时候依然能够加载视图。
3,PerformSeletor
4,常驻线程
创建一个Runloop在子线程一直运行,保证线程在后台常驻(AFNetworking源码)。

子线程的Runloop需要手动调用,然后添加一个Source或者Timer事件,再调用Run方法。

5,自动释放池
Runloop内部会自动创建一个自动释放池,开始的时候创建,等到合适的时机再释放,通过观察Runloop状态来进行。

6,通过对Runloop添加Observer来做一些事情
(1),比如监听点击事件,当runloop处理点击事件时候可以统一做一些事情。
(2),也可以通过对Runloop状态的观察来检测系统卡顿,当长时间处于一个模式不变就是出现了卡顿。

//创建子线程监控
dispatch_async(dispatch_get_global_queue(0, 0), ^{
    //子线程开启一个持续的 loop 用来进行监控
    while (YES) {
        long semaphoreWait = dispatch_semaphore_wait(dispatchSemaphore, dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC));
        if (semaphoreWait != 0) {
            if (!runLoopObserver) {
                timeoutCount = 0;
                dispatchSemaphore = 0;
                runLoopActivity = 0;
                return;
            }
            //BeforeSources 和 AfterWaiting 这两个状态能够检测到是否卡顿
            if (runLoopActivity == kCFRunLoopBeforeSources || runLoopActivity == kCFRunLoopAfterWaiting) {
                //将堆栈信息上报服务器的代码放到这里
            } //end activity
        }// end semaphore wait
        timeoutCount = 0;
    }// end while
});

你可能感兴趣的:(iOS 中Runloop)