Runloop机制和用处

Objective-C Runloop机制

对于RunLoop而言最核心的事情就是保证线程在没有消息的时候休眠,在有消息时唤醒,以提高程序性能。RunLoop这个机制是依靠系统内核来完成的(苹果操作系统核心组件Darwin中的Mach)。
RunLoop 实际上是一个对象,这个对象在循环中用来处理程序运行过程中出现的各种事件(比如说触摸事件、UI刷新事件、定时器事件、Selector事件),从而保持程序的持续运行。
RunLoop 在没有事件处理的时候,会使线程进入睡眠模式,从而节省 CPU 资源,提高程序性能。
在线程创建后,在创建对应的RunLoop
RunLoop由系统维护在一张表中,其中线程为Key对应的Value是创建的RunLoop

NSTimer,具体化应用

本质上来讲,NSTimer就是封装的Runloop的最简单体现应用
NSTimer的创建通常有两种方式,尽管都是类方法,一种是timerWithXXX,另一种scheduedTimerWithXXX
二者最大的区别就是后者除了创建一个定时器外会自动以NSDefaultRunLoopModeMode添加到当前线程RunLoop中,不添加到RunLoop中的NSTimer是无法正常工作的。
//滚动UIScrollView(UITableView、UICollectionview是类似的)的情况下Timer都会暂停
-(NSTimer *)timer1{
    if(_timer1 == nil){
        //无法运行,用scheduledTimerWithTimeInterval创建的timer对象必须要放到NSDefaultRunLoopMode中
        _timer1 = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(timeInterval:) userInfo:nil repeats:YES];
    }
    return _timer1;
}

-(NSTimer *)timer2{
    if(_timer2 == nil){
        _timer2 = [NSTimer timerWithTimeInterval:1.0f target:self selector:@selector(timeInterval:) userInfo:nil repeats:YES];
        [[NSRunLoop currentRunLoop]addTimer:_timer2 forMode:NSDefaultRunLoopMode];
    }
    return _timer2;
}

生命周期

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

额外用处

//延迟方法的执行,在延迟4s并且在滑动结束后调用
[self.imageView performSelector:@selector(setImage:) withObject:[UIImage imageNamed:@"tupian"] afterDelay:4.0 inModes:@[NSDefaultRunLoopMode]];

源码备注

int32_t __CFRunLoopRun()
{
    // 通知即将进入runloop ------(声明周期一)------
    __CFRunLoopDoObservers(KCFRunLoopEntry);
    
    do
    {
        // 通知将要处理timer和source  ------(声明周期二和三)------
        __CFRunLoopDoObservers(kCFRunLoopBeforeTimers);
        __CFRunLoopDoObservers(kCFRunLoopBeforeSources);
        // 处理非延迟的主线程调用
        __CFRunLoopDoBlocks();
        // 处理Source0事件
        __CFRunLoopDoSource0();
        
        if (sourceHandledThisLoop) {
            __CFRunLoopDoBlocks();
         }
        /// 如果有 Source1 (基于port) 处于 ready 状态,直接处理这个 Source1 然后跳转去处理消息。
        if (__Source0DidDispatchPortLastTime) {
            Boolean hasMsg = __CFRunLoopServiceMachPort();
            if (hasMsg) goto handle_msg;
        }
        /// 通知 Observers: RunLoop 的线程即将进入休眠(sleep)。 ------(声明周期四)------
        if (!sourceHandledThisLoop) {
            __CFRunLoopDoObservers(runloop, currentMode, kCFRunLoopBeforeWaiting);
        }
        // GCD dispatch main queue
        CheckIfExistMessagesInMainDispatchQueue();
        // 即将进入休眠。 ------(声明周期五)------
        __CFRunLoopDoObservers(kCFRunLoopBeforeWaiting);
        // 等待内核mach_msg事件
        mach_port_t wakeUpPort = SleepAndWaitForWakingUpPorts();
        // 等待。。。
        // 从等待中醒来
        __CFRunLoopDoObservers(kCFRunLoopAfterWaiting);
        // 处理因timer的唤醒
        if (wakeUpPort == timerPort)
            __CFRunLoopDoTimers();
        // 处理异步方法唤醒,如dispatch_async
        else if (wakeUpPort == mainDispatchQueuePort)
            __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__()
        // 处理Source1
        else
            __CFRunLoopDoSource1();
        // 再次确保是否有同步的方法需要调用
        __CFRunLoopDoBlocks();
    } while (!stop && !timeout);
    // 通知即将退出runloop
    __CFRunLoopDoObservers(CFRunLoopExit);
}

你可能感兴趣的:(Runloop机制和用处)