performselector实现原理(详解performselector应用场景)

RunLoop 学习起来是很抽象,也不好理解,所以一定多看几次,多学学才能学好!这也是中高级 iOS 必须掌握的知识点,面试中经常遇到

什么是 RunLoop?

Run 表示运行,Loop 表示循环。结合在一起就是运行循环的意思。RunLoop 就是在程序运行过程中循环做一些事情.

RunLoop 的应用范畴有哪些?

定时器 (Timer)、PerformSelector

GCD Async Main Queue

事件响应、手势识别、界面刷新

网络请求

AutoreieasePool

上面这些底层都是 RunLoop 在支撑,说白了,如果没有 RunLoop 支撑,上面的这些都无法实现。

如果没有 RunLoop 会发生什么呢?像我们的命令行项目,创建出来默认就是没有 RunLoop,请看下图

中高级 iOS 必备知识点之 RunLoop而我们 iOS 项目的 main 函数里面都有 UIApplicationMain(argc, argv, nil, appDelegateClassName);这个代码,这里就是创建了一个主线程的 RunLoop,所以我们程序不会退出,一直在运行中。我们可以大致写一下 main 函数里面的伪代码如下:

中高级 iOS 必备知识点之 RunLoop

RunLoop 的基本作用

1.保持程序的持续运行

2.处理 App 中的各种事件(比如触摸事件、定时器事件等)

3.节省了 CPU 资源,提高程序性能:该做事时做事,该休息时休息

获取 RunLoop 对象

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

Foundation : NSRunLoop (OC 语言里面的)

Core Foundation : CFRunLoopRef (C 语言里面的)

NSRunLoop 和 CFRunLoopRef 都代表着 RunLoop 对象

NSRunLoop 是基于 CFRunLoopRef 的一层 OC 包装

CFRunLoopRef 是开源的.(CFRunLoopRef 参考链接)

其实我们很多都是由 OC 包装出来的,请看下面:

中高级 iOS 必备知识点之 RunLoop获取当前 RunLoop 和主线程 RunLoop

中高级 iOS 必备知识点之 RunLoop这里注意 “地址不一样” 因为 NSRunLoop 是对 CFRunLoopDef 做了一层包装,你可以用 OC 的 NSLog(“%@”,[NSRunLoop MainRunLoop]) 获取对比一下,它的地址就是 C 语言获取的地址。主线程只有一个 RunLoop。

RunLoop 与线程

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

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

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

RunLoop 会在线程结束时销毁

主线程的 RunLoop 已经自动创建,子线程默认没有开启 RunLoop。

中高级 iOS 必备知识点之 RunLoop由于源码不能像 objc 直接打开,我们把它拉到项目中查看。

中高级 iOS 必备知识点之 RunLoop那我们就继续来了解 RunLoop 内部的数据结构,到底是怎么工作的。

RunLoop 相关的类

Core Foundation 中关于 RunLoop 的 5 个类

1.CFRunLoopRef

2.CFRunLoopModeRef

3.CFRunLoopSourceRef

4.CFRunLoopTimerRef

5.CFRunLoopObserverRef

再看下 CFRunLoopRef 的底层源码:

中高级 iOS 必备知识点之 RunLoop这个 mode 就是 CFRunLoopModeRef 类型,所以里面存储一堆的 CFRunLoopModeRef 类型的 mode。

而 _currentMode 也是 CFRunLoopModeRef 这个类型,所以我们很容易得出一个结论:

一个 RunLoop 对象里面有一堆的 mode,也就是存在 _modes 里面,里面只有一个是 _currentMode。

我们再窥探一下源码,看下 mode 里面存储的是什么?

中高级 iOS 必备知识点之 RunLoop

中高级 iOS 必备知识点之 RunLoop

CFRunLoopModeRef

1.CFRunLoopModeRef 它是代表 RunLoop 的运行模式;

2.一个 RunLoop 包含若干个 Mode,每个 Mode 又包含若干个Source0/Source1/Timer/Observer;

3.RunLoop 启动时只能选择其中一个 Mode,作为 currentMode;

4.如果需要切换 Mode,只能退出当前 RunLoop,再重新选择一个 Mode 进入;

5.不同组的Source0/Source1/Timer/Observer 能分割开来,互不影响;

6.如果 Mode 里面没有任何Source0/Source1/Timer/Observer,RunLoop 会立马退出;

如果只能在一种模式下运行,对性能什么的都有很大好处,比如我在滑动模式下,不考虑不滑动的模式,所以就不会卡顿,顺畅很多。还有注意的就是,它切换 mode 是在循环里面切换的,所以不会导致程序退出。

常见的 mode 有 2 种,其他情况很少见,所以掌握这两个一般都是没问题了

1.KCFRunLoopDefaultMode (NSDefaultRunLoopMode):App 的默认 Mode,通常是主线程是在这个 Mode 下运行;

2.UITrackingRunLoopMode : 界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响;

RunLoop 到底做哪些事?

RunLoop 在不停执行的时候到底具体做了哪些事?其实是 RunLoop 在不停循环的时候,就是处理每个 mode 下的 Source0、Source1、Timer、Observer 这里面的事件,那我们就来看看这里面具体对应的到底是什么事件。

Source0

触摸事件、performSelector:onThread:

比如我们的 touchbegin 这个我们看下下面的代码:

中高级 iOS 必备知识点之 RunLoop基于 Port 的线程间的通信,系统事件的捕捉。

(两个线程之间相互传递消息的处理,系统事件捕捉,其实也包括触摸事件,只是把事件捕捉到以后传递给 Source0)。

Timer

NSTimer 定时器,performSelector:withObject:afterDelay (这个方法的底层实现也就是 NSTimer 来实现的)。

Observers

用于监听 RunLoop 的状态,UI 的刷新 (BeforeWaiting),Autorelease pool(BeforeWaiting)。

(在 RunLoop 休眠之前都会去执行 UI 的刷新啊、Autorelease pool 的释放等)

以上这些东西,完全就是我们平时开发中经常写的代码,比如设置背景色,设置 frame 等等。

由于 RunLoop 知识点比较多,如果写太多不利于大家的阅读和消化,所以其他内容放在后面介绍!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 ivillcn@qq.com 举报,一经查实,本站将立刻删除。文章链接:https://www.zhangei.com/n/2706.html

(0)
上一篇 2023年10月21日 下午6:31
下一篇 2023年10月21日 下午6:34

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注