iOS:底层原理之 Runloop

在这里插入图片描述

应用范畴

  • 定时器(Timer)、PerformSelector
  • GCD Async Main Queue
  • 事件响应、手势识别、界面刷新
  • 网络请求
  • AutoreleasePool
    在这里插入图片描述在这里插入图片描述

RunLoop 的基本作用

  • 保持程序的持续运行
  • 处理App中的各种事件(比如触摸事件、定时器事件等)
  • 节省CPU资源,提高程序性能:该做事时做事,该休息时休息

iOS 中有 2 套 API 来访问和使用 RunLoop

  • Foundation:NSRunLoop
  • Core Foundation:CFRunLoopRef
  • NSRunLoop和CFRunLoopRef都代表着RunLoop对象
  • NSRunLoop是基于CFRunLoopRef的一层OC包装
  • CFRunLoopRef是开源的
  • https://opensource.apple.com/tarballs/CF/

[NSRunLoop currentRunLoop];
CFRunLoopGetCurrent( );

NS*** 是对CF***Ref进行了一层封装。

  • 每条线程都有唯一的一个与之对应的RunLoop对象

  • RunLoop保存在一个全局的Dictionary里,线程作为key,RunLoop作为value

  • 线程刚创建时并没有RunLoop对象,RunLoop会在第一次获取它时创建

  • RunLoop会在线程结束时销毁

  • 主线程的RunLoop已经自动获取(创建),子线程默认没有开启RunLoop

  • Foundation

    • [NSRunLoop currentRunLoop]; // 获得当前线程的RunLoop对象
    • [NSRunLoop mainRunLoop]; // 获得主线程的RunLoop对象
  • Core Foundation

    • CFRunLoopGetCurrent(); // 获得当前线程的RunLoop对象
    • CFRunLoopGetMain(); // 获得主线程的RunLoop对象
      在这里插入图片描述
  • CFRunloopRef

    • CFRunLoopModeRef
      • CFRunLoopSourceRef-0
      • CFRunLoopSourceRef-1
      • CFRunLoopObserverRef
      • CFRunLoopTimerRef

CFRunloopModeRef 模式

  • CFRunLoopModeRef 代表 RunLoop 的运行模式
  • 一个 RunLoop 包含若干个 Mode,每个 Mode 又包含若干个 Source0/Source1/Timer/Observer
  • RunLoop 启动时只能选择其中一个 Mode,作为 currentMode
  • 如果需要切换 Mode,只能退出当前 Loop,再重新选择一个 Mode 进入
    • 不同组的 Source0/Source1/Timer/Observer 能分隔开来,互不影响
  • 如果 Mode 里没有任何 Source0/Source1/Timer/Observer,RunLoop会立马退出
常见的2种Mode
  • kCFRunLoopDefaultMode(NSDefaultRunLoopMode):App的默认Mode,通常主线程是在这个Mode下运行
  • UITrackingRunLoopMode:界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响

RunLoop的六种状态

在这里插入图片描述
添加 Observer 监听 RunLoop 的所有状态
在这里插入图片描述

运行逻辑

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
_CFRUNLOOP_IS_CALLING_OUT_TO***

RunLoop 在实际开中的应用

  • 控制线程生命周期(线程保活)
  • 解决 NSTimer 在滑动时停止工作的问题
  • 监控应用卡顿
  • 性能优化
线程保活(常驻线程)

AFNetworking使用RunLoop技术对子线程进行管理。让子线程不销毁,用的时候随时使用。
runloop 如果没有任何 source/source0 timer/observer 就会退出。
================== 目的:线程保活===============
在NSThread的Target方法里添加下面代码:

// 往 RunLoop 里面添加 Source\Timer\Observer
[NSRunLoop currentRunLoop] addPort:[[NSPort alloc] init] forMode:NSDefaultRunLoopMode];
[NSRunLoop currentRunLoop] run];
// 做事情,睡觉,做事情,睡觉… ...
// 将某个方法在某个线程中执行
[self performSelector:@selector(test) onThread:self.thread withObject:nil waitUntilDone:NO];
// waitUntilDone: 是否等到此方法执行完成再往下进行

停止上面的RunLoop
在相应线程中(子线程)执行:

CFRunLoopStop(CFRunLoopGetCurrent( )); //    停止当前所在的RunLoop

[NSRunLoop currentRunLoop] run];

底层在重复的调用:

[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];

用于开启一个无线的循环,如使用 CFRunLoopStop(CFRunLoopGetCurrent( )); 进行停止当前的runloop,只能够停止其中的一次,但他是无限循环的,所以无法停止。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值