iOS Runloop

作者: 人魔七七 | 来源:发表于2018-08-03 16:27 被阅读9次

    Runloop 是一种这样的机制。接受timer或者source 任务,当有任务的时候处理,没有任务的时候休眠。

    NSRunloop 并不是线程安全的,而CFRunloopRef 是安全的。

    CFRunloopRef 大致的数据结构如下:

    里面会有一个锁,每次访问mode list。
    一个唤醒与runloop 关联线程的端口
    一个保存NSRunloopCommonModes 表示的mode set
    添加到NSRunloopCommonModes中的source timer 等item
    runloop 当前执行的哪个mode
    该runloop 所有的mode

    CFRunLoopModeRef中能用到的常用的结构如下:
    所有的source0 source1 set
    所有的timer数组
    所有的观察者数组

    线程和runloop密切相关,现有线程再有runloop。我们不用显示的创建,CFRunLoopGetMain() 和 CFRunLoopGetCurrent(),分别用于获取MainRunLoop和当前线程的RunLoop。大致有一个全局字典以线程为key ,以runloop 为value 的字典。我们只要在合适的时候启动就可以了。

    // 往RunLoop 的 Mode 中添加一个timer

    • (void)addTimer:(NSTimer *)timer forMode:(NSRunLoopMode)mode;
      // 往RunLoop的 Mode 中添加一个source1任务
    • (void)addPort:(NSPort *)aPort forMode:(NSRunLoopMode)mode;
      // 从RunLoop的 Mode 里删除source1 任务
    • (void)removePort:(NSPort *)aPort forMode:(NSRunLoopMode)mode;

    大致的执行过程如下:

    苹果公开提供kCFRunLoopDefaultMode (NSDefaultRunLoopMode) 和 UITrackingRunLoopMode。可以自定添加相应的模式。

    如果要在自己创建的线程中处理东西,如果是处理一次可以不需要runloop。但是如果想App 的网络请求,经常性发生,频繁的创建会消耗资源,我们用runloop 来线程保活。

    子线程创建后所有的任务放到自动释放池里面,为什么呢?您的应用程序将泄漏对象,如果您的应用程序或线程是长期存在的和潜在的生成大量生成对象,内存会积攒。

    如果在主线程滚动的scrollView 还有其他操作,NSDefaultRunLoopMode会变成UITrackingRunLoopMode,这样其他操作无法执行,我们可以设置把其他操作到runloop 其他的模式 [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

    ,或者创建一个其他的辅助线程来处理这样互相不影响,但是在当前线程的runloop必须运行起来。

    NSRunLoopCommonModes 是一个set 集合。会在模式切换后添加到再添加到set 中。

    我们可以用runloop 优化tableView 流畅度。下载渲染设置图片会在UITrackingRunLoopMode 中进行这样会比较卡。可以把设置的过程放到其他模式中。或者一次runloop渲染一次,分多次渲染。

    我们可以用它来检测App 卡顿。 主线程添加一个观察者,检测从 kCFRunLoopBeforeSources 到 kCFRunLoopBeforeWaiting 花费的时间 是否过长。如果花费的时间大于某一个阙值,我们就认为有卡顿,并把当前的线程堆栈转储到文件中,并在以后某个合适的时间,将卡顿信息文件上传到服务器。

    参考链接:

    https://blog.csdn.net/u011619283/article/details/53765643

    相关文章

      网友评论

        本文标题:iOS Runloop

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