一、什么是RunLoop
a、RunLoop实质上是一个死循环,保证程序持续运行,只有程序退出的时候才会结束。如下,在main.m文件中:
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
//开启主线程,同时默认开启主线程的RunLoop。
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
二、RunLoop使用原理和注意点
a、一个RunLoop包含若干个Mode,每个Mode又包含若干个Source、Observer、Timer
b、每次RunLoop启动,只能指定一个Mode,这个Mode被称为CurrentMode
c、如果需要切换Mode,只能退出Loop,再重新指定一个Mode进入, 以使不同组之间的Source、Observer、Timer互不受影响
三、RunLoop和线程的关系
a、RunLoop与线程一一对应,且是管理线程的。
b、RunLoop在主线程默认开启,在子线程中是懒加载。线程执行完毕之后进入休眠状态,有任务就会被唤醒。
c、RunLoop在第一次获取时被创建,在线程结束时被销毁。
d、对于子线程中的定时器,由于RunLoop是懒加载,只有我们使用的时候才会创建,所以要确保子线程的RunLoop被创建,不然定时器不会回调。
NSRunLoop *loop = [NSRunLoop currentRunLoop];
[loop run];
NSTimer和RunLoop的关系:
a、在子线程中,要启动分线程的RunLoop,NSTimer才能执行。因为分线程的RunLoop是默认关闭的。
NSTimer *timer = [NSTimer timerWithTimeInterval:1.f target:self selector:@selector(update) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
四、RunLoop常用的两种模式
a、NSDefaultRunLoopMode,默认模式,主线程中的RunLoop默认是NSDefaultRunLoopMode
b、UITrackingRunLoopMode,在滚动式图的情况下RunLoop处于此模式下。常见的场景为TableView、CollectionView、ScrollView的滑动对定时器的影响。
场景分析:
由于一个RunLoop不能同时使用两个RunLoopMode,所以当视图滚动的时候,RunLoop从默认模式的NSDefaultRunLoopMode跳转到UITrackingRunLoopMode。由于定时器还是NSDefaultRunLoopMode模式,所以会停止。我们只要把定时器的RunLoop的模式设定为NSRunLoopCommonModes(占位Mode)即可。
五、常用的使用场景
a、异步线程下下载图片,如果失败该怎么处理呢?
在此异步线程中启动一个RunLoop重新发送网络请求,下载图片。
b、需要执行一个耗时操作,该怎么处理?
开启一个异步子线程,启动它的RunLoop来执行该耗时操作。
c、在分线程中开启一个异步请求,会有什么问题?
我们需要判断请求是否结束,如果没有结束,要保持线程一直启动,直道结束的时候自动关闭。
//创建一个线程,调用NSTimer事件
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(update) object:nil];
// 设置线程的优先级(0.0 - 1.0,1.0最高级)
thread.threadPriority = 1;
// 开启线程
[thread start];
- (void)update{
NSLog(@"----------分线程线程的定时器启动:%@",[NSThread currentThread]);
@autoreleasepool{
NSTimer *timer = [NSTimer timerWithTimeInterval:1.f target:self selector:@selector(newThing) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
//在分线程中如果不开启RunLoop,那么定时器是无法执行的
// NSRunLoop *loop = [NSRunLoop currentRunLoop];
// [loop addPort:[NSMachPort port] forMode:NSRunLoopCommonModes];
//
// [loop run];
}
}
未开启分线程RunLoop.png
开启分线程RunLoop.png
网友评论