这是我参与8月更文挑战的第27天,活动详情查看:8月更文挑战
开启一个常驻线程(让一个子线程不进入消亡状态,等待其他线程发来消息,处理事件)
在子线程中,当任务执行完毕之后子线程就会被销毁,如果我们需要开启一个子线程,在程序运行过程中永远都存在,那么我们就会面临一个问题,如何让子线程永远活着,这时就要用到常驻线程。所谓常驻线程只需在这个线程的mode中添加(Source、Timer、Observer任意一个即可),那么这个线程中的 RunLoop 就可以跑起来,当需要将 RunLoop 停掉的时候,直接调用类似- (void)removePort:(NSPort *)aPort forMode:(NSRunLoopMode)mode方法移除即可。
-
通过在 RunLoop 中添加
Timer实现常驻线程@interface ThreadViewController () @property (strong, nonatomic) NSThread *thread; @end @implementation ThreadViewController - (void)viewDidLoad { [super viewDidLoad]; self.thread = [[NSThread alloc]initWithTarget:self selector:@selector(run) object:nil]; [self.thread start]; } - (void)run{ //NSThred创建额子线程需要手动管理内存 @autoreleasepool{ [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(log) userInfo:nil repeats:YES]; //启动runloop NSLog(@"runloop---start--"); [[NSRunLoop currentRunLoop] run]; NSLog(@"runloop---end--"); } } - (void)log{ NSLog(@"%@",[NSThread currentThread]); }log:
-
通过在 RunLoop 中添加
Source实现常驻线程@interface ThreadViewController () @property (strong, nonatomic) NSThread *thread; @end @implementation ThreadViewController - (void)viewDidLoad { [super viewDidLoad]; self.thread = [[NSThread alloc]initWithTarget:self selector:@selector(run) object:nil]; [self.thread start]; } - (void)run{ @autoreleasepool{ //在当前子线程的runloop中的mode中添加端口(其实就是加了source,有了source,runloop就可以跑起来) [[NSRunLoop currentRunLoop]addPort:[NSPort port] forMode:NSDefaultRunLoopMode]; //启动runloop NSLog(@"runloop---start--"); [[NSRunLoop currentRunLoop] run]; NSLog(@"runloop---end--"); } } - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ //在 self.thread 线程中调用log [self performSelector:@selector(log) onThread:self.thread withObject:nil waitUntilDone:YES]; } - (void)log{ NSLog(@"%@",[NSThread currentThread]); }log:
可以让某些事件在特定模式下执行
网络下载的图片,如果显示在 UIScrollView、UITableView上,当滑动屏幕的时候,UI有时会卡顿,解决这个问题可以用 RunLoop
//假如后台下载图片已经完成,此刻仍在滑动屏幕,那么可以延迟显示,当你停止滑动屏幕的时候再显示,此刻只需将runloop模式改为NSDefaultRunLoopMode。
- (void)viewDidLoad {
[super viewDidLoad];
[self showImage];
}
- (void)showImage{
//只在NSDefaultRunLoopMode模式下显示
[self.imageView performSelector:@selector(setImage:) withObject:[UIImage imageNamed:@"aa"] afterDelay:3 inModes:@[NSDefaultRunLoopMode]];
}
添加Observer控制事件响应
可以添加 Observer 监听 RunLoop 的状态,比如监听点击事件的处理(在所有点击事件之前做一些事情)
- (void)observer{
/*
添加Observer
参数1:默认值
参数2:监听活动(这里监听了kCFRunLoopAllActivities)
参数3:重复
参数4:0
*/
CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
NSLog(@"---监听Runloop状态改变--%lu",activity);
});
/*
添加观察者,监听Runloop的在kCFRunLoopDefaultMode模式下的状态
参数1:当前runloop
参数2:监听者
参数3:模式
*/
CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);
//释放Observer
CFRelease(observer);
}
log: