RunLoop应用场景
- 开启一个常驻线程(让一个子线程不进入消亡状态,等待其他线程发来消息,处理其他事件)
- 在子线程中开启一个定时器(或添加port)
- 在子线程中进行一些长期监控
- 可以控制定时器在哪种模式下运行
- 可以让某些事件(行为、任务)在特定模式下执行
- 可以添加Observer监听RunLoop的状态,比如监听点击事件的处理(在所有点击事件之前做一些事情)
常驻线程
让一个子线程不进入消亡状态,等待其他线程发来消息,处理其他事件
-
声明一个NSThread属性:
@property (nonatomic, strong) NSThread *thread
; -
开启线程
- (void)viewDidLoad { [super viewDidLoad]; self.thread = [[NSThread alloc]initWithTarget:self selector:@selector(run) object:nil]; [self.thread start]; } -(void)run{ //RunLoop如果当前mode中没有任何Sources(Source0、Source1)、Timer,那么就会直接退出RunLoop @autoreleasepool { //在此线程开启RunLoop ---> 让线程不死 [[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSDefaultRunLoopMode]; //添加port相当于添加Source [[NSRunLoop currentRunLoop] run]; } }
注意:常驻线程启动RunLoop最好放到autoreleasepool里面
作用:清掉创建的临时变量(主线程的RunLoop会自动在RunLoop睡眠前释放旧的释放池然后自动创建新的释放池,子线程的RunLoop最好添加个大释放池包裹住)
-
往常驻线程中发送消息
[self performSelector:@selector(work) onThread:self.thread withObject:nil waitUntilDone:NO];
常驻线程的好处
- 让一个子线程不进入消亡状态,等待其他线程发来消息,处理其他事件(AFNetworking框架里面就使用了常驻线程)
定时器与RunLoop
控制定时器在哪种模式下运行
NSTimer:
- scheduledTimerWithTimeInterval ---- 自动添加到当前RunLoop中,而且是NSDefaultRunLoopMode,可手动修改模式
- timerWithTimeInterval ---- 需要手动添加到runLoop
NSTimer *timer=[NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(timer) userInfo:nil repeats:YES];
//将定时器放入RunLoop中
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
模式:
- NSDefaultRunLoopMode:一旦RunLoop进入其他模式(例如滚动的mode),这个定时器就不会工作
- NSRunLoopCommonModes:将定时器加入到标记为common modes的模式下,只要RunLoop知道有这个模式的存在,不管RunLoop在哪个模式都会执行这个标记的模式(即使在滚动的UITrackingRunLoopMode下也会执行)
Observer与RunLoop
添加Observer监听RunLoop的状态,比如监听点击事件的处理(在所有点击事件之前做一些事情)
//创建观察者
CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
//状态改变时回调的block
NSLog(@"RunLoop状态 %lu",activity);
});
//添加观察者:监听RunLoop的状态
//参数1:线程的RunLoop对象
//参数2:观察者
//参数3:需要监听RunLoop对象所在的模式
CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);
//ARC模式下C语言层面的对象需要手动释放内存
//释放Observer
CFRelease(observer);
注意:创建了Observer记得要release
RunLoop的状态
- kCFRunLoopEntry = (1UL << 0), //即将进入loop 1
- kCFRunLoopBeforeTimers = (1UL << 1), //即将处理Timer 2
- kCFRunLoopBeforeSources = (1UL << 2), //即将处理Sources 4
- kCFRunLoopBeforeWaiting = (1UL << 5), //即将进入休眠 32
- kCFRunLoopAfterWaiting = (1UL << 6), //刚从休眠中唤醒 64
- kCFRunLoopExit = (1UL << 7), //即将退出loop 128
- kCFRunLoopAllActivities = 0x0FFFFFFFU //所有状态
UL是无符号长整数的意思
1UL<<0:0b00000001
1UL<<1:0b00000010
1UL<<2:0b00000100
1UL<<3:0b00001000
0x0FFFFFFF是整形int变量里能保存的最大数
让某些事件(行为、任务)在特定模式下执行
设置图片不在滚动视图滚动期间显示
[self.imageView performSelector:@selector(setImage:) withObject:[UIImage imageNamed:@"01"] afterDelay:3.0 inModes:@[NSDefaultRunLoopMode]];