iOS底层原理-Runloop

作者: 我是一只攻城狮_ifYou | 来源:发表于2018-07-25 14:31 被阅读24次

Runloop

Runloop作用:

  • 保持程序的持续运行
  • 处理程序的各种事件(触摸事件、定时器事件等)
  • 节约CPU资源,提高程序性能

程序中Main函数中的UIApplicationMain函数主要作用就是创建了一个主运行循环
主线程几乎所有的事情都是交给了runloop去完成,比如UI界面的刷新,点击事件的处理,performSelector等等,但并非所有的任务都是由runloop完成

Runloop有两种形式:

  • OC语言-- NSRunloop
  • C语言 -- CFRunloopRef

Runloop与线程的关系:

  • 每一条线程都有一个与之对应的runloop对象
  • runloop保存在全局的字典内,是以线程为key,runloop为value
  • 线程刚创建时没有runloop对象的,runloop会在第一次获取他的时候创建
  • runloop在线程销毁时销毁

Runloop与Mode的关系:

Snip20180601_27.png

Runloop只能选择其中一个mode,称之为CurrentMode
如果需要切换mode,只能退出当前mode,重新选择一个Mode进入
不同组的source0,source1,observers,timer能分隔开,互不影响

注:如果mode里没有任何source0等等的事件,则runloop会立马退出
切换mode也是在Runloop内部,不会导致程序退出

常见的2种Mode:

  • kCFRunloopDefaultMode //程序的默认Mode
  • UITrackingRunloopMode //界面追踪Mode

注:kCFRunloopCommonModes默认包括了kCFRunloopDefaultMode和UITrackingRunloopMode
kCFRunloopCommonModes并不是一个真正的模式,只是一个标记,而kCFRunloopDefaultMode和UITrackingRunloopMode的模式是真正意义的模式,timer在设置了kCFRunloopCommonModes标记的模式下都能运行,而kCFRunloopDefaultMode和UITrackingRunloopMode这两个模式都是kCFRunloopCommonModes标记的,

使用NSRunloop方式和CFRunloopRef的方式获取两者,会发现地址不一致,实际是NSRunloop是对CFRunloopRef的一层封装,其本质地址还是CFRunLoopRef的地址

注:(lldb)bt可以获取函数调用栈

Mode中各个成员的含义:

  • source0:
    1.触摸事件
    2.performSelector :OnThread

  • source1
    1.基于Port的线程间通信
    2.系统事件的捕捉

  • Timer
    1.NSTimer
    2.performSelector :afterDelay//这句代码的本质是往Runloop中添加定时器

  • Observers
    1.监听runloop的状态
    2.UI刷新(在runloop休眠之前)
    3.自动释放池(在runloop休眠之前)

Runloop运行逻辑:

Snip20180604_1.png

Runloop处理事件一般都是调用_CFRUNLOOP_IS_CALLING_OUT_TO_XXXX函数进行事件处理

GCD中当仅在子线程做事情时,是不依赖Runloop的,但当需要回到主线程等线程间操作的时候,需要runloop来执行

线程休眠其实和线程阻塞类似,但和通过代码例如while(1)令线程阻塞是不一样的,使用代码while(1),线程并未休眠,而是不断进行while(1)判断,汇编也并未停止,而线程休眠是可以真正意义上做到令线程不做任何的事情

Runloop休眠的实现原理: 会从用户态切换到内核的内核态,在内核态执行休眠的目的,是可以实现真正意义上的休眠(即没有消息就是休眠,有消息就唤醒,并回到用户态)

Runloop响应用户操作具体流程:先通过source1事件进行捕捉,然后再source0事件进行处理

Runloop在实际开发中的应用:

  • 线程保活
  • 解决NSTimer在滑动中停止工作的问题
  • 监控应用卡顿
  • 性能优化

  • 解决NSTimer在滑动中停止工作的问题:
    timer是在默认模式下工作的,所以在滑动中(uitracking)的模式下是会停止工作的
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1 
                                                 repeats:YES          
                                                 block:^(NSTimer * _Nonnull timer) {
            
        }
        
//带有schedule的是会将定时器直接添加到默认的模式

NSTimer *timer = [NSTimer timerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
            
        }]
//该方法不会添加到默认模式去,只会单纯创建一个timer
//后续需要手动调用runloop的addtimer方法才能令定时器工作
  • 线程保活

Runloop的run方法是一个无线的循环,故外部停止runloop只是停止其中一次循环,故是无法停止Runloop的,run方法用于开启一个永不销毁的线程

使用runMode方法在唤醒后,做完对应事情,runloop就会退出

performSelector方法的waitUntilDone设置为YES,代表该语句执行完后才会执行后面的语句,设置为NO,则后面语句与该语句是一起执行的

GCD只负责创建线程,不负责线程保活

一个问题:

Q:保住线程的命为什么要用Runloop,用强指针不就好了?
A:准确的说,使用Runloop是为了让线程保持激活状态,线程的任务一旦执行完毕,生命周期就结束,无法再使用

相关文章

  • Runloop

    Runloop 实现原理及应用iOS - RunLoop 底层源码详解及具体运用

  • RunLoop

    详细文章 xx_cc - iOS底层原理总结 - RunLoop 意一ineyee - RunLoop RunLo...

  • 探寻RunLoop的本质

    iOS底层原理总结 - RunLoop 面试题 讲讲 RunLoop,项目中有用到吗? RunLoop内部实现逻辑...

  • iOS底层原理——浅谈RunLoop

    RunLoop应用:线程保活 线程保活、控制销毁 iOS-浅谈RunLoop8iOS底层原理总结 - RunLoo...

  • RunLoop相关

    iOS底层原理总结 - RunLoop解密 Runloop Runloop是一种在当前线程,持续调度各种任务的运行...

  • Today面试

    Runloop 底层原理Kvo 底层原理ARC 底层原理 如何实现GCD 底层原理Block 底层原理Aut...

  • iOS底层原理-Runloop

    Runloop Runloop作用: 保持程序的持续运行 处理程序的各种事件(触摸事件、定时器事件等) 节约CPU...

  • 【iOS 底层原理】Runloop

    一. RunLoop简介 运行循环,在程序运行过程中循环做一些事情,如果没有Runloop程序执行完毕就会立即退出...

  • iOS底层原理 - RunLoop

    序言:关于RunLoop简书有很多技术牛人已经讲述的很详细了,而且不管是项目中或是工作中都会使用到,这段时间看了M...

  • iOS底层原理--Runloop

    所谓的Runloop其实就是死循环总共有5种模式 每条线程都有一个runloop 但是默认够不开启循环 作用a. ...

网友评论

    本文标题:iOS底层原理-Runloop

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