RunLoop的实质是一个死循环,用于保证程序的持续运行,只有当程序退出的时候才会结束
1。保证线程的长时间存活
2。处理App中的各种事件(触摸、定时器、Selector事件)
3。节省CPU资源,提高程序性能(该做事做事,没事做休息)
RunLoop相关类:
CFRunLoopRef:代表RunLoop的对象
CFRunLoopModeRef:RunLoop的运行模式
CFRunLoopSourceRef:就是RunLoop模型图中提到的输入源/事件源
CFRunLoopTimerRef:就是RunLoop模型图中提到的定时源
CFRunLoopObserverRef:观察者,能够监听RunLoop的状态改变
RunLoop模式常用有3个:
NSDefaultRunLoopMode->默认模式,主线程中默认是NSDefaultRunLoopMode
UITrackingRunLoopMode->视图滚动模式,RunLoop会处于该模式下
NSRunLoopCommonModes->并不是真正意义上的Mode,是一个占位用的“Mode”,默认包含了NSDefaultRunLoopMode和UITrackingRunLoopMode两种模式
runloop和线程的关系:
主线程Runloop已经创建好了,子线程的runloop需要手动创建 ;一条线程对应一个RunLoop对象,每条线程都有唯一一个与之对应的RunLoop对象。一般来讲,一个线程一次只能执行一个任务,执行完成后线程就会退出
runloop的实际使用:
1。RunLoop运行模式对NSTimer定时器的影响。
NSTimer的定时器是受运行模式影响的,而开发中我们有时候彻底去除这种影响,很显然,NSTimer定时器不能做到这点,这时,我们可以使用GCD的定时器。
2。ImageView推迟显示-->实现图片加载性能优化
当界面中含有UITableView,而且每个UITableViewCell里边都有图片。这时候当我们滚动UITableView的时候,如果有一堆的图片需要显示,那么可能会出现卡顿的现象。
2.1. 监听UIScrollView的滚动
因为UITableView继承自UIScrollView,所以我们可以通过监听UIScrollView的滚动,实现UIScrollView相关delegate即可。
2.2. 利用PerformSelector设置当前线程的RunLoop的运行模式
利用 performSelector 方法为UIImageView调用 setImage: 方法,并利用 inModes 将其设置为RunLoop下NSDefaultRunLoopMode运行模式。
[self.imageView performSelector:@selector(setImage:) withObject:[UIImage imageNamed:@"tupian"] afterDelay:4.0 inModes:NSDefaultRunLoopMode];
这样我们就实现了在拖动完之后,在延迟显示UIImageView。
3。后台常驻线程
我们在开发应用程序的过程中,如果后台操作特别频繁,经常会在子线程做一些耗时操作(下载文件、后台播放音乐等),我们最好能让这条线程永远常驻内存。
- (void)viewDidLoad {
[super viewDidLoad];
// 创建线程,并调用run1方法执行任务
self.thread = [[NSThread alloc] initWithTarget:self selector:@selector(run1) object:nil];
[self.thread start];
}
- (void) run1{
NSLog(@"----run1-----");
// 添加下边两句代码,就可以开启RunLoop,之后self.thread就变成了常驻线程,可随时添加任务,并交于RunLoop处理
[[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] run];
// 测试是否开启了RunLoop,如果开启RunLoop,则来不了这里,因为RunLoop开启了循环。
NSLog(@"未开启RunLoop");
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
// 利用performSelector,在self.thread的线程中调用run2方法执行任务
[self performSelector:@selector(run2) onThread:self.thread withObject:nil waitUntilDone:NO];
}
- (void) run2{
NSLog(@"----run2------");
}
经过运行测试,除了之前打印的 ----run1----- ,每当我们点击屏幕,都能调用 ----run2------ 。
这样我们就实现了常驻线程的需求。