RunLoop 理解

2017-08-01  本文已影响34人  bonoCat

Runloop解析

概述

do{

}while (1)

从字面的意思来看,就是运行循环,没有终点,一直运行。下面先看下大致 runloop 运行模式

从官方图可以看出,在线程开始的时候就开始运行,知道某个时间点。运行的过程中,会有事件插入(port、custom、performSelector)、timer,这个时候runloop会提醒线程去处理相关的事,其他时间,线程处于休眠状态。

相关类

从图中可以看出一个 Runloop 包含多个 Mode

typedef struct __CFRunLoopMode *CFRunLoopModeRef;

有 5 种 mode

KCFRunLoopDefaultMode // 默认 Mode
UITrackingRunLoopMode // 保证页面滑动不受影响
KCFRunLoopCommonModes  // 占位 Mode
UIInitializationRunLoopMode // 刚启动时使用
GSEventReceiveRunLoopMode   /// 系统事件内部Mode

每种 mode 包含 一组 source、timer、observer

typedef struct __CFRunLoopSource * CFRunLoopSourceRef;
typedef struct __CFRunLoopObserver * CFRunLoopObserverRef;
typedef struct __CFRunLoopTimer * CFRunLoopTimerRef;

看下都有什么作用

CFRunLoopTimerRef

将定时器添加到指定 Mode ,在指定 Mode 下运行

- (void)timer
{
    NSTimer *timer = [[NSTimer alloc] initWithFireDate:[NSDate new] interval:1 repeats:YES block:^(NSTimer *timer) {

        NSLog(@"执行了%@", timer);

    }];

    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
}

CFRunLoopSourceRef

事件源:

1.Port-Based Sources 从其他线程或内核发出
2.custom Input Sources 自定义

  1. perform Selector Sources

可以从函数调用栈来区分source 0 source 1

 UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(0, 100, 100, 100)];
    btn.backgroundColor = [UIColor redColor];
    [btn addTarget:self action:@selector(btnClick) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:btn];

栈调用关系.png

从上面可以看出点击,是source 0 事件

还有就是 perform Selector 的使用方式

- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay inModes:(NSArray<NSRunLoopMode> *)modes;

就可以指定performSelector在某个Mode下运行

CFRunLoopObserverRef

runloop 状态监控

/* Run Loop Observer Activities */
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
    kCFRunLoopEntry = (1UL << 0),   /// 即将进入RunLoop
    kCFRunLoopBeforeTimers = (1UL << 1), /// 即将处理 Timer
    kCFRunLoopBeforeSources = (1UL << 2), /// 即将处理 Sources
    kCFRunLoopBeforeWaiting = (1UL << 5), /// 即将进入休眠
    kCFRunLoopAfterWaiting = (1UL << 6), /// 从休眠中唤醒
    kCFRunLoopExit = (1UL << 7), /// 即将退出RunLoop
    kCFRunLoopAllActivities = 0x0FFFFFFFU /// 活跃中
};

通过对 RunLoop 监控,可以知道线程的状态,比如空闲时处理一些事情

 CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAfterWaiting, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
        
        
    });
    
    /*  不能主动创建 RunLoop
     CFRunLoopGetMain()
     CFRunLoopGetCurrent()
     */
    
    CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);

逻辑处理

作用

1.保证程序一直运行

int main(int argc, char * argv[]) {
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

程序启动的时候,就会启动一个runloop,使得 main 函数不会有返回值。除非用户主动关闭,或者各种崩溃,或超时,也就是为什么我们app崩溃时候回进入 main 函数。

/* Reasons for CFRunLoopRunInMode() to Return */
enum {
    kCFRunLoopRunFinished = 1,
    kCFRunLoopRunStopped = 2,
    kCFRunLoopRunTimedOut = 3,
    kCFRunLoopRunHandledSource = 4
};

2.app各种事件处理(滑动、定时器、performSelector)

3.节省cpu资源

上一篇下一篇

猜你喜欢

热点阅读