Runloop
运行循环,在程序运行过程中循环做一些事情.
应用范畴:
- 保持程序的持续运行
- 定时器 performSelector
- GCD Async Main Queue
- 事件响应 手势识别 界面刷新
- 网络请求
- AutoreleasePool
Runloop与线程
- 每条线程都有唯一的一个与之对应的
Runloop
对象. -
Runloop
保存在一个全局的字典里面,线程最为.key
,runloop
最为value
. - 第一次获取的时候自动创建.
-
Runloop
线程结束时候销毁. - 主线程的
Runloop
自动创建,子线程默认没有开启Runloop
.
获取RunLoop对象
- Foundation:NSRunloop
- Core Foundation:CFRunloopRef
NSRunLoop *runloop;
CFRunLoopRef runloop2;
runloop = [NSRunLoop currentRunLoop];
runloop2 = CFRunLoopGetCurrent();
[NSRunLoop mainRunLoop];//主线程runloop
RunLoop相关的类
CFRunLoopRef
CFRunLoopModeRef
CFRunLoopSourceRef
CFRunLoopTimeRef
CFRunLoopObserverRef
CFRunLoopRef
底层结构
typedef struct CF_BRIDGED_MUTABLE_TYPE(id) __CFRunLoop * CFRunLoopRef;
struct __CFRunLoop {
...
pthread_t _pthread;
uint32_t _winthread;
CFMutableSetRef _commonModes;
CFMutableSetRef _commonModeItems;
CFRunLoopModeRef _currentMode;
CFMutableSetRef _modes;//集合包含各种CFRunLoopModeRef对象
...
};
CFRunLoopModeRef
底层结构
struct __CFRunLoopMode {
...
CFStringRef _name;
CFMutableSetRef _sources0;//(集合包含CFRunLoopSourceRef)
CFMutableSetRef _sources1;
CFMutableArrayRef _observers;//数组包含CFRunLoopObserverRef
CFMutableArrayRef _timers;//数组包含CFRunLoopTimeRef
...
};
CFRunLoopModeRef
常见2种mode
-
kCFRunLoopDefaultModel
(NSDefaultRunLoopMode
),App默认mode,通常主线程处于这个mode下. -
UITrackingRunLoopMode
:界面跟踪Mode,用于ScrollView追踪滑动触摸,保证界面滑动时候不受其他mode影响.
source0
- 触摸事件处理
performSelectoreThread
source1
- 基于
port
的线程间通信 - 系统事件捕捉
timers
NSTimer
performSelector: withObject: afterDelay:
observers
- 监听
runloop
状态 UI刷新
CFRunLoopObserverRef
有几种模式
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
NSRunLoop *runloop;
CFRunLoopRef runloop2;
runloop = [NSRunLoop currentRunLoop];
runloop2 = CFRunLoopGetCurrent();
CFRunLoopObserverRef observer = CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopAllActivities, YES, 0, MyCFRunLoopObserverCallBack, NULL);
CFRunLoopAddObserver(runloop2, observer, kCFRunLoopCommonModes);
CFRelease(observer);
}
/*
kCFRunLoopEntry = (1UL << 0),
kCFRunLoopBeforeTimers = (1UL << 1),
kCFRunLoopBeforeSources = (1UL << 2),
kCFRunLoopBeforeWaiting = (1UL << 5),
kCFRunLoopAfterWaiting = (1UL << 6),
kCFRunLoopExit = (1UL << 7),
kCFRunLoopAllActivities = 0x0FFFFFFFU
*/
void MyCFRunLoopObserverCallBack(CFRunLoopObserverRef observer,
CFRunLoopActivity activity,
void *info)
{
switch (activity) {
case kCFRunLoopEntry:
NSLog(@"kCFRunLoopEntry");
break;
// case kCFRunLoopBeforeTimers:
// NSLog(@"kCFRunLoopBeforeTimers");
// break;
// case kCFRunLoopBeforeSources:
// NSLog(@"kCFRunLoopBeforeSources");
// break;
// case kCFRunLoopBeforeWaiting:
// NSLog(@"kCFRunLoopBeforeWaiting");
// break;
// case kCFRunLoopAfterWaiting:
// NSLog(@"kCFRunLoopAfterWaiting");
// break;
case kCFRunLoopExit:
NSLog(@"kCFRunLoopExit");
break;
default:
break;
}
}
-
CFRunLoopModeRef
代表RunLoop
的运行模式. - 一个
RunLoop
包含若干个Mode
,每个Mode
又包含若干个/sources0/sources1/observers/timers
. -
RunLoop
启动时候只能选择一个mode
,作为currentMode
. - 切换
Mode
,只能退出当前Loop
,再重新选择mode
.
流程图
实际应用
- 控制线程声明周期(线程保活)
- 解决NSTimer在滑动时候停止工作
- 监控应用卡顿
- 性能优化
线程保活
@interface ViewController ()
@property (nonatomic,strong) MyThread *thread;
@property (nonatomic,assign) BOOL isStop;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self.thread start];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
if (self.isStop) {
return;
}
[self performSelector:@selector(test) onThread:self.thread withObject:nil waitUntilDone:YES];
}
- (void)test{
NSLog(@"test");
}
- (IBAction)stopXib:(id)sender {
if (self.isStop) {
return;
}
[self performSelector:@selector(stopThread) onThread:self.thread withObject:nil waitUntilDone:YES];
}
- (void)stopThread{
self.isStop = YES;
CFRunLoopStop(CFRunLoopGetCurrent());
}
- (MyThread *)thread{
if (!_thread) {
__weak typeof(self) weakSelf = self;
_thread = [[MyThread alloc]initWithBlock:^{
NSLog(@"---begin----%@",[NSThread currentThread]);
[[NSRunLoop currentRunLoop]addPort:[NSPort new] forMode:NSDefaultRunLoopMode];
// [[NSRunLoop currentRunLoop]run];
while (weakSelf && !weakSelf.isStop) {
[[NSRunLoop currentRunLoop]runMode:NSDefaultRunLoopMode beforeDate: [NSDate distantFuture]];
}
NSLog(@"---end----%@",[NSThread currentThread]);
}];
}
return _thread;
}
- (void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
}
- (void)dealloc{
NSLog(@"%s",__func__);
[self stopXib:nil];
}
接口封装
.h
typedef void(^MyTaskBlock)(void);
@interface MyPermenantThread : NSObject
- (void)run;
- (void)executeTask:(MyTaskBlock)block;
- (void)stop;
@end
.m
@interface MyPermenantThread()
@property (nonatomic,strong) MyThread *innerThread;
@property (nonatomic,assign,getter=isStopped) BOOL stopped;
@end
@implementation MyPermenantThread
- (instancetype)init
{
self = [super init];
if (self) {
__weak typeof (self) weakSelf = self;
self.innerThread = [[MyThread alloc]initWithBlock:^{
[[NSRunLoop currentRunLoop]addPort:[NSPort new] forMode:NSDefaultRunLoopMode];
while (weakSelf && !weakSelf.isStopped) {
[[NSRunLoop currentRunLoop]runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
};
}];
}
return self;
}
- (void)run{
if (!self.innerThread) {
return;
}
[self.innerThread start];
}
- (void)executeTask:(MyTaskBlock)block{
if (!self.innerThread || !block) {
return;
}
[self performSelector:@selector(__executeTask:) onThread:self.innerThread withObject:block waitUntilDone:NO];
}
- (void)stop{
if (!self.innerThread) {
return;
}
[self performSelector:@selector(__stop) onThread:self.innerThread withObject:nil waitUntilDone:YES];
}
- (void)dealloc{
[self stop];
}
#pragma mark -- private methods
- (void)__stop{
self.stopped = YES;
CFRunLoopStop(CFRunLoopGetCurrent());
self.innerThread = nil;
}
- (void)__executeTask:(MyTaskBlock)block
{
block();
}
@end
c语言实现
NSLog(@"begin");
CFRunLoopSourceContext context = {0} ;
CFRunLoopSourceRef source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context);
CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
while (weakSelf && !weakSelf.isStopped) {
//第三个参数 执行完退出YES.
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1.0e10, true);
}
CFRelease(source);
NSLog(@"end");