生命之源-RunLoop


iOS一切的生命之源都需要RunLoop的支持,关于RunLoop的界面和相关知识,网上想你一一搜一天也看不完,所以这里只为总结Runloop相关技术,适用于底层,面试,简单实战了解!

前言:

1
+ 一个线程只能执行一个任务,任务执行完之后,线程就会退出,但是主线程不会退出,因为我们需要让主线程等待接收事件

介绍

1
2
3
4
5
6
+ 运行循环(do-while):不断处理各种事件
+ 一个线程(唯一)对应一个RunLoop(可以嵌套子runloops),主线程默认启动,子线程手动启动(run):获取RunLoop对象的时候,就会创建RunLoop
+ RunLoop有多个Model,Model有多个timer(array)/sourceset)/observer(array)。
+ 每次启动只能启动一个,切换需要先推出在指定(分隔不同time/source/observer)
+ 当前Model没有任何timer/source/observer就会推出(mode只能添加不能删除)
+ 第一次获取创建,线程结束销毁

runloop退出的条件:

1
app退出;线程关闭;设置最大时间到期;modeItem为空;

Ref

1
2
3
4
5
+ CFRunLoopTimerRef,基于时间触发(NSTimer),受Model影响,GCD不受Model影响
+ CFRunLoopSourceRef,事件源,source0(非Port),source1(Port),跟Port密切联系

source0:event事件,只含有回调,需要标记待处理(signal),然后手动将runloop唤醒(wakeup);
source1 :包含一个 mach_port 和一个回调,被用于通过内核和其他线程发送的消息,能主动唤醒runloop。

Runloop本质:mach port和mach_msg()。

1
2
3
Mach是XNU的内核,进程、线程和虚拟内存等对象通过端口发消息进行通信,Runloop通过mach_msg()函数发送消息,如果没有port 消息,内核会将线程置于等待状态 mach_msg_trap() 。如果有消息,判断消息类型处理事件,并通过modeItem的callback回调(处理事件的具体执行是在DoBlock里还是在回调里目前我还不太明白???)。

Runloop有两个关键判断点,一个是通过msg决定Runloop是否等待,一个是通过判断退出条件来决定Runloop是否循环

定时源,输入源

1
2
+ 定时源,同步消息,特定或者一定时间间隔发生
+ 输入源,来自起来线程或者程序

应用

1
+ NSTimer,ImageView显示,PerformSelector,常驻线程,自动释放池,界面刷新,手势识别,GCD任务,timer:(与CADisplayLink),网络请求:

autorrelease释放时机:

1
2
+ 手动干预释放:指定autorreleasepool,当前作用域大括号结束立即释放
+ 系统自动释放:不指定,aut对象在当前RunLoop迭代结束释放

自动释放池

1
2
自动释放池寄生于Runloop:程序启动后,主线程注册了两个Observer监听runloop的进出与睡觉。一个最高优先级OB监测Entry状态;一个最低优先级OB监听BeforeWaiting状态和Exit状态。
线程(创建)-->runloop将进入-->最高优先级OB创建释放池-->runloop将睡-->最低优先级OB销毁旧池创建新池-->runloop将退出-->最低优先级OB销毁新池-->线程(销毁)

Timer注意

1
2
1、如果是在主线程中运行timer,想要timer在某界面有视图滚动时,依然能正常运转,那么将timer添加到RunLoop中时,就需要设置mode 为NSRunLoopCommonModes。
2、如果是在子线程中运行timer,那么将timer添加到RunLoop中后,Mode设置为NSDefaultRunLoopMode或NSRunLoopCommonModes均可,但是需要保证RunLoop在运行,且其中有任务。

runloop:

1
2
1、(要让马儿跑)通过do-while死循环让程序持续运行:接收用户输入,调度处理事件时间。
2、(要让马儿少吃草)通过mach_msg()让runloop没事时进入trap状态,节省CPU资源。
坚持原创技术分享,您的支持将鼓励我继续创作!