我爱编程

RunLoop

2018-04-14  本文已影响16人  前年的邂逅_Jerry

一、RunLoop是事件接受与分发机制的一个实现。

二、RunLoop中的五种模式:

1. kCFRunLoopDefaultMode:App的默认Mode,通常主线程是在这个Mode下运行
2. UITrackingRunLoopMode:界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响
3. UIInitializationRunLoopMode: 在刚启动 App 时第进入的第一个 Mode,启动完成后就不再使用
4. GSEventReceiveRunLoopMode: 接受系统事件的内部 Mode,通常用不到
5. kCFRunLoopCommonModes: 这是一个占位用的Mode,作为标记kCFRunLoopDefaultMode和UITrackingRunLoopMode用,并不是一种真正的Mode

三、每个RunLoop中有多个Model Item,每个Model item包含如下:<Set>Source、<Array>Time、<Array>Observe。

四、Source种类

1、基于Port
2、自定义的
链接:https://www.cnblogs.com/ioshe/p/5489112.html

五、Time。

定时器

六、Observe

-(void)observerCreate{
    //1.创建监听者
    /*
      第一个参数:怎么分配存储空间
      第二个参数:要监听的状态 。kCFRunLoopAllActivities 所有的状态
      第三个参数:是否持续监听
      第四个参数:优先级 总是传0
      第五个参数:当状态改变时候的回调
      */
    CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
        switch (activity) {
            case kCFRunLoopEntry:
                NSLog(@"即将进入runloop");
                break;
            case kCFRunLoopBeforeTimers:
                NSLog(@"即将处理timer事件");
                break;
            case kCFRunLoopBeforeSources:
                NSLog(@"即将处理source事件");
                break;
            case kCFRunLoopBeforeWaiting:
                NSLog(@"即将进入睡眠");
                break;
            case kCFRunLoopAfterWaiting:
                NSLog(@"被唤醒");
                break;
            case kCFRunLoopExit:
                NSLog(@"runloop退出");
                break;

            default:
                break;
        }
    });

    //2.添加监听者
    /*
       第一个参数:要监听哪个runloop
       第二个参数:观察者
       第三个参数:运行模式
       */
    CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);
}

7、应用场景:

1、在runloop中添加定时器。定时器在不同模式上切换。
2、延迟执行performSelecter: withObject: afterDelay相关方法是怎样被执行的?在子线程中也是一样的吗?
在子线程中添加performSelecter: withObject: afterDelay实际上是将定时器添加到runLoop中,需要[[NSRunLoop currentRunLoop] run];才能执行performSelect方法,执行完后会自动将时间源移除,不用考虑僵尸线程的问题。僵尸线程讲解链接:https://www.jianshu.com/p/a20c4bdf3415

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [self performSelector:@selector(performSelect) withObject:nil afterDelay:3];
        NSRunLoop * runLoop = [NSRunLoop currentRunLoop];
         NSLog(@"runloop = %@",runLoop);
        [[NSRunLoop currentRunLoop] run];
    });
- (void)performSelect{
    NSLog(@"%s",__func__);
}
runLoop打印结果:
runloop = <CFRunLoop 0x7ffe1c609fe0 [0x1063b17b0]>{wakeup port = 0x5807, stopped = false, ignoreWakeUps = true, 
current mode = (none),
common modes = <CFBasicHash 0x7ffe1c60ad40 [0x1063b17b0]>{type = mutable set, count = 1,
entries =>
    2 : <CFString 0x1063d1b40 [0x1063b17b0]>{contents = "kCFRunLoopDefaultMode"}
}
,
common mode items = (null),
modes = <CFBasicHash 0x7ffe1c60a0a0 [0x1063b17b0]>{type = mutable set, count = 1,
entries =>
    2 : <CFRunLoopMode 0x7ffe1c609420 [0x1063b17b0]>{name = kCFRunLoopDefaultMode, port set = 0x5707, timer port = 0x590b, 
    sources0 = (null),
    sources1 = (null),
    observers = (null),
    timers = <CFArray 0x7ffe1c609f50 [0x1063b17b0]>{type = mutable-small, count = 1, values = (
    0 : <CFRunLoopTimer 0x7ffe1c60e5c0 [0x1063b17b0]>{valid = Yes, firing = No, interval = 0, tolerance = 0, next fire date = 545451740 (2.99986506 @ 32529849429331), callout = (Delayed Perform) ViewController performSelect (0x1057f7f97 / 0x105667c70) (/Users/Jerry/Library/Developer/CoreSimulator/Devices/D7925E35-7007-42DD-929E-C26FA54C8468/data/Containers/Bundle/Application/CDCE0849-7D22-4C4E-BE8F-12A4EAB35075/Demo1.app/Demo1), context = <CFRunLoopTimer context 0x7ffe1c60ccf0>}
)},
    currently 545451737 (32526849538688) / soft deadline in: 2.99989061 sec (@ 32529849429331) / hard deadline in: 2.99989035 sec (@ 32529849429331)
},

}
}

另一种使用方法:

    dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 2.2*NSEC_PER_SEC);
    dispatch_after(time, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSRunLoop * runLoop = [NSRunLoop currentRunLoop];
        NSLog(@"runloop = %@",runLoop);
        [self performSelect];
    });

3、NSPort来产生常驻线程。

参考链接:http://www.imlifengfeng.com/blog/?p=487
4、AF2.6.3之前,请求网络时,将请求数据的子线程放在DefaultModel和TrackingModel下。
参考链接https://blog.csdn.net/u011619283/article/details/53433243

上一篇下一篇

猜你喜欢

热点阅读