查看oc文件底层结构
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc xxx.m
支持ARC、指定运行时系统版本
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-15.0.0 xxx.m
一、RunLoop基础
1. RunLoop对象
-
iOS
中有两套API
来访问和使用RunLoop
-
Foundation
:NSRunLoop
-
Core Foundation
:CFRunLoopRef
-
-
RunLoop
和CFRunloopRef
都代表着RunLoop
对象-
NSRunloop
是基于CFRunLoopRef
的一层OC包装 -
CFRunLoopRef
是开源的
-
-
Foundation
-
[NSRunLoop currentRunLoop];
获得当前线程的RunLoop
对象 -
[NSRunLoop mainRunLoop];
获得主线程的RunLoop
对象
-
-
Core Foundation
-
CFRunLoopRefGetCurrent();
获得当前线程的RunLoop
对象 -
CFRunLoopRefGetMain();
获得主线程的RunLoop
对象
-
注:https://opensource.apple.com/tarballs/CF/
- 程序并不会马上退出,而是保持运行状态
-
RunLoop
的基本作用- 保持程序的持续运行
- 处理App中各种事件(如:触摸事件、定时器事件等)
- 节省CPU资源,提高程序性能:该做事时做事,该休息时休息
-
……
2 . RunLoop与线程
- 每条线程都有唯一的一个与之对应的
RunLoop
对象 -
RunLoop
保存在一个全局的Dictionary
里,线程作为key
,RunLoop
作为value
- 线程刚创建时并没有
RunLoop
对象,RunLoop
会在第一次获取它时创建 -
RunLoop
会在线程结束时销毁 - 主线程的
RunLoop
已经自动获取(创建),子线程默认没有开启RunLoop
3. RunLoop相关的类
- Core Foundation中关于RunLoop的5个类
CFRunLoopRef
CFRunLoopModeRef
CFRunLoopSourceRef
CFRunLoopTimerRef
CFRunLoopObserverRef
typedef struct __CFRunLoop * CFRunLoopRef;
struct __CFRunLoop {
pthread_t _pthread;
CFMutableSetRef _commonModes;
CFMutableSetRef _commonModeItems;
CFRunLoopModeRef _currentMode;
CFMutableSetRef _modes;
};
typedef struct __CFRunLoopMode *CFRunLoopModeRef;
struct __CFRunLoopMode {
CFStringRef _name;
CFMutableSetRef _sources0;
CFMutableSetRef _sources1;
CFMutableArrayRef _observers;
CFMutableArrayRef _timers;
};
-
CFRunLoopModeRef
-
CFRunLoopModeRef
代表RunLoop
的运行模式 - 一个
RunLoop
包含若干个Mode
,每一个Mode
又包含若干个sources0
/sources1
/Timer
/observer
-
RunLoop
启动时只能选择其中一个Mode
作为currentMode
- 如果需要切换
Mode
,只能退出当前Loop
,再重新选择一个Mode
进入- 不同组的
sources0
/sources1
/Timer
/observer
能分隔开来,互不影响
- 不同组的
- 如果
Mode
里没有sources0
/sources1
/Timer
/observer
,RunLoop
会立马退出 - 常见的两种Mode
-
kCFRunLoopDefaultMode
(NSDefaultRunLoopMode
):App的默认Mode,通常主线程是在这个Mode下运行 -
UITrackingRunLoopMode
:界面跟踪Mode
,用于ScrollView
追踪触摸滑动,保证界面滑动时不受其他Mode
影响
-
-
CFRunLoopObserverRef
/* Run Loop Observer Activities */
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
kCFRunLoopEntry = (1UL << 0), //即将进入Loop
kCFRunLoopBeforeTimers = (1UL << 1), // 即将处理Timer
kCFRunLoopBeforeSources = (1UL << 2), // 即将处理Source
kCFRunLoopBeforeWaiting = (1UL << 5), // 即将进入休眠
kCFRunLoopAfterWaiting = (1UL << 6), // 刚从休眠中唤醒
kCFRunLoopExit = (1UL << 7), // 即将退出Loop
kCFRunLoopAllActivities = 0x0FFFFFFFU
};
二、RunLoop的运行逻辑
- Source0
- 触摸事件处理
performSelector:onThread:
- Source1
- 基于Port的线程间通信
- 系统事件捕捉
- Timers
- NSTimer
performSelector:withObject:afterDelay:
- Observers
- 用于监听
RunLoop
的状态 - UI刷新(
BeforeWaiting
) -
Autorelease pool
(BeforeWaiting
)
- 用于监听
三、RunLoop休眠的实现原理
- 等待消息
- 没有消息就让线程休眠
-
有消息就唤醒线程
四、RunLoop在实际的应用
- 控制线程生命周期(线程保活)
- 解决
NSTimer
在滑动时停止工作的问题 - 监控应用卡顿
- 性能优化
注:可能涉及的面试题
- 讲讲
RunLoop
,项目中有用到吗 -
RunLoop
内部实现逻辑 -
RunLoop
和线程的关系 -
timer
与RunLoop
的关系 - 程序中添加每3秒响应一次的
NSTimer
,当拖动tableView
时timer
可能无法响应要怎么解决 -
RunLoop
是怎么响应用户操作的,具体流程是什么样的 - 说说
RunLoop
的几种状态 -
RunLoop
的mode
作用是什么
上一篇:
OC底层基础:Block
下一篇:
OC底层基础:多线程GCD