什么是RunLoop
运行循环,可以在程序运行中做一些事情(处理source、timer、observer),一个线程对应一个RunLoop,主线程默认开启RunLoop,子线程需要手动触发,我们一个iOS应用就是启动了RunLoop一直在循环(UIApplicationMain
),所以程序才没有退出。
RunLoop应用
- 定时器(timer)、PerfromSelector
- GCD Async main queue
- 事件响应、手势识别、界面刷新
- 网络请求
- AutoReleasePool
…………
RunLoop的基本作用
- 保持程序持续运行
- 处理App的各种事件(触摸、定时器)
- 节省cpu资源、提高程序性能,该做事的时候做事,该休息的时候休息
RunLoop结构
我们先看图:
runloop结构
每个RunLoop里面会保留一个_pthread
线程对象,一个RunLoop对应一个_pthread
,_currentMode
为当前RunLoop的时运行模式,一个模式包含了_source0
、_source1
、_observers
,_timers
,一个RunLoop同一个时间点只能运行一个模式currentMode
。
RunLoop运行逻辑
RunLoop运行逻辑大致了解一下,RunLoop里面在循环处理Blocks、Timer、Source、Observer、GCD等操作,处理结束会进入休眠,唤醒又会继续处理操作
RunLoop在开发中的应用
- 控制线程声明周期 (线程保活)
- 处理NSTimer在滑时停止工作
- 监听应用卡顿
- 性能优化
处理NSTimer在滑时停止工作
因为RunLoop从静止状态切换到滑动状态的时候是切换Mode的,从NSDefaultRunLoopMode
切换到UITrackingRunLoopMode
,而定时器的处理是在NSDefaultRunLoopMode
中,所以这里的解决方案是把定时器加入到NSRunLoopCommonModes
中
控制线程声明周期 (线程保活)
一个线程执行完他的事情后,线程就会销毁,而我们开发中有时候需要一个常驻线程,用于处理一些耗时的操作,而我们一直创建线程、销毁线程是比较消耗性能的一件事, 所以,我们必须在程序运行中保护好该线程,这里就需要使用到RunLoop
例子如下:
#import "ViewController.h"
#import "MJThread.h"
@interface ViewController ()
@property (nonatomic,assign)BOOL isStop;
@property (nonatomic,strong)MJThread *thread;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
__weak typeof(self)weakSelf = self;
self.isStop = NO;
self.thread = [[MJThread alloc] initWithBlock:^{
NSLog(@"---begin---");
[[NSRunLoop currentRunLoop] addPort:[[NSPort alloc] init] forMode:NSDefaultRunLoopMode];
while (weakSelf && !weakSelf.isStop) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
NSLog(@"---end---");
}];
[self.thread start];
}
- (IBAction)stop {
if (!self.thread) return;
[self performSelector:@selector(stopAction) onThread:self.thread withObject:nil waitUntilDone:YES];
}
- (void)stopAction {
self.isStop = YES;
CFRunLoopStop(CFRunLoopGetCurrent());
self.thread = nil;
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
// 执行
if (!self.thread) return;
[self performSelector:@selector(run) onThread:self.thread withObject:nil waitUntilDone:YES];
}
- (void)run {
NSLog(@"------%s----%@---",__func__,[NSThread currentThread]);
}
@end
这里,我们启动一个线程,在线程中获取RunLoop,因为子线程的RunLoop默认是没有东西的,如果不往RunLoop里面添加东西的话,它就会了立刻结束,所以我们在这里添加一个NSPort
对象,接下来我们进入一个While循环执行runMode
,在我理解里,runMode
方法类似RunLoop的一次循环,这里进入了休眠,而我们加入一个while
循环,就可以实现我们手动控制它循环,只有当我们手动把标记换掉后,停止RunLoop,循环才会结束,线程就会销毁
网友评论