美文网首页
Runloop源码分析(4)——addTimer

Runloop源码分析(4)——addTimer

作者: 无悔zero | 来源:发表于2021-01-21 22:51 被阅读0次

先看看Runloop最常见的应用,滑动页面时定时器会停止,所以要处理:

NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
    NSLog(@"1");
}];
[[NSRunLoop currentRunLoop] addTimer:timer forMode: NSRunLoopCommonModes];

原因:

RunLoopMode可以切换,默认为kCFRunLoopDefaultMode,滑动时为UITrackingRunLoopMode,启动时为UIInitializationRunLoopModetimer加入的RunLoopMode默认是kCFRunLoopDefaultMode,当页面滑动时,RunLoopMode自动切换到UITrackingRunLoopMode,因此timer失效。当停止滑动时,RunLoopMode又切换回kCFRunLoopDefaultModetimer恢复。

  1. 我们从源码看看做了什么:
void CFRunLoopAddTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeName) {    
    ...
    if (modeName == kCFRunLoopCommonModes) {
        CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;//<CFSetRef>{defaultMode, TrackingMode}
        if (NULL == rl->_commonModeItems) {
            rl->_commonModeItems = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks);//懒加载
        }
        CFSetAddValue(rl->_commonModeItems, rlt);//添加timer
        if (NULL != set) {
            CFTypeRef context[2] = {rl, rlt};
            CFSetApplyFunction(set, (__CFRunLoopAddItemToCommonModes), (void *)context);//遍历_commonModes,将 timer 添加到 commonModes 的所有模式下
            CFRelease(set);
        }
    } else {
        CFRunLoopModeRef rlm = __CFRunLoopFindMode(rl, modeName, true);//找到相关mode
        ...
    }
    __CFRunLoopUnlock(rl);
}
static void __CFRunLoopAddItemToCommonModes(const void *value, void *ctx) {
    CFStringRef modeName = (CFStringRef)value;
    CFRunLoopRef rl = (CFRunLoopRef)(((CFTypeRef *)ctx)[0]);
    CFTypeRef item = (CFTypeRef)(((CFTypeRef *)ctx)[1]);
    if (CFGetTypeID(item) == CFRunLoopSourceGetTypeID()) { ... } else if (CFGetTypeID(item) == CFRunLoopObserverGetTypeID()) {
        ...
    } else if (CFGetTypeID(item) == CFRunLoopTimerGetTypeID()) {
        CFRunLoopAddTimer(rl, (CFRunLoopTimerRef)item, modeName);//再调用
    }
}

解决:

timer加入到kCFRunLoopCommonModes后,会将timer加入_commonModeItems中,并将timer加入commonModes的所有mode中,所以不管页面滑动还是静止,(在所有Runloop模式中)timer都能生效。

相关文章

  • Runloop源码分析(4)——addTimer

    先看看Runloop最常见的应用,滑动页面时定时器会停止,所以要处理: 原因:RunLoopMode可以切换,默认...

  • 36.iOS底层学习之RunLoop

    本章提纲:1、RunLoop基础知识2、RunLoop的数据结构3、RunLoop的相关源码分析4、RunLoop...

  • RunLoop学习资料

    非常好的runloop学习系列 CoreFoundation源码 RunLoop系列之源码分析 关于Runloop...

  • RunLoop 源码分析

    此篇主要分析 RunLoop 的源码,对源码的注释在仓库中。 分析源码我主要采用的是: RunLoop 相关的结构...

  • iOS中的定时器

    NSTimer 创建方式: 创建定时器 需要添通过addTimer:forMode:加到当前线程的runloop ...

  • 【高级iOS】autoreleasepool源码分析,并与run

    【高级iOS】autoreleasepool源码分析,并与runloop的关系

  • 学习RunLoop

    runloop源码地址:源码下载 runloop官方介绍:查看文档 runloop的源码在corefundatio...

  • RunLoop源码分析

    之前一直对ios的RunLoop机制一知半解,很多地方不是很清楚于是每次想到这个问题都会纠结,想搞明白这里边到底做...

  • RunLoop源码分析

    一、RunLoop的入口 通过再touchesBegan方法中添加断点,使用bt指令,可以显示出方法调用栈 从下到...

  • RunLoop源码分析

    文章涉及的代码 源码分析:LFRunLoop 测试Demo:LFRunLoopDemo RunLoop是iOS中...

网友评论

      本文标题:Runloop源码分析(4)——addTimer

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