RunLoop

作者: 前年的邂逅_Jerry | 来源:发表于2018-04-14 20:12 被阅读16次

    一、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

    相关文章

      网友评论

        本文标题:RunLoop

        本文链接:https://www.haomeiwen.com/subject/xgbqkftx.html