在开发场景中,有可能需要对某条线程保活,让这条线程在有事情做的时候进行工作,没有事情做的时候进行休眠。
技术点
- NSRunLoop
- NSTread
-
利用
NSThread
创建一条线程,并且在这条线程创建一个RunLoop
,并创建一个source
,防止RunLoop
退出,这里也可以新建一个集成于NSThread
的类,观察NSThread
是否被释放,同时创建一个标志属性stopped
初始值为NO
来判断是否要退出RunLoop
.- (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor whiteColor]; self.stopped = NO; __weak typeof(self) weakSelf = self; self.thread = [[YXCThread alloc] initWithBlock:^{ // 给当前线程创建一个 runLoop ,并且创建一个 source NSLog(@"beigin %@", [NSThread currentThread]); [[NSRunLoop currentRunLoop] addPort:[NSPort new] forMode:NSDefaultRunLoopMode]; while (weakSelf && !weakSelf.isStopped) { [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; } NSLog(@"end %@", [NSThread currentThread]); }]; // 线程开启 [self.thread start]; }
-
紧接着,模拟做事情,这里选择是在
touchesBegan:withEvent:
去模拟做一些事情- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { if (!self.thread) return; // waitUntilDone 这里可以传 NO,不需要等待当前操作执行完成 [self performSelector:@selector(doSomeThing) onThread:self.thread withObject:nil waitUntilDone:NO]; }
- (void)doSomeThing { NSLog(@"%s, %@", __func__, [NSThread currentThread]); }
-
最后在 ViewController 中的 dealloc 方法中,停止 runLoop 和 释放线程操作
- (void)dealloc { NSLog(@"%s", __func__); // waitUntilDone 这里需要传 YES,等待操作完成了,再继续执行,不然控制器释放了,会崩溃 [self performSelector:@selector(stop) onThread:self.thread withObject:nil waitUntilDone:YES]; }
-
最后输出结果
beigin <YXCThread: 0x600003d033c0>{number = 7, name = (null)} -[YXCController doSomeThing], <YXCThread: 0x600003d033c0>{number = 7, name = (null)} -[YXCController doSomeThing], <YXCThread: 0x600003d033c0>{number = 7, name = (null)} -[YXCController doSomeThing], <YXCThread: 0x600003d033c0>{number = 7, name = (null)} -[YXCController doSomeThing], <YXCThread: 0x600003d033c0>{number = 7, name = (null)} -[YXCController doSomeThing], <YXCThread: 0x600003d033c0>{number = 7, name = (null)} -[YXCController dealloc] end <YXCThread: 0x600003d033c0>{number = 7, name = (null)} -[YXCThread dealloc]
这样,就对一条线程保活完成了,最后控制器释放了,Thread
也释放了,RunLoop
也释放了
下面,可以进行封装一下
新建一个 YXCPermanentThread
类
.h 文件
@interface YXCPermanentThread : NSObject
#pragma mark - Method
- (void)executeTask:(void (^)(void))task;
@end
.m 文件
#pragma mark ====== YXCThread ======
@interface YXCThread : NSThread
@end
@implementation YXCThread
- (void)dealloc {
NSLog(@"%s", __func__);
}
@end
#pragma mark ====== YXCPermanentThread ======
@interface YXCPermanentThread ()
@property (nonatomic, strong) YXCThread *thread; /**< 开辟子线程 */
@property (nonatomic, assign, getter=isStopped) BOOL stopped; /**< 是否停止runLoop */
@end
@implementation YXCPermanentThread
- (instancetype)init {
if (self = [super init]) {
self.stopped = NO;
__weak typeof(self) weakSelf = self;
self.thread = [[YXCThread alloc] initWithBlock:^{
NSLog(@"-- beigin -- %@", [NSThread currentThread]);
[[NSRunLoop currentRunLoop] addPort:[[NSPort alloc] init] forMode:NSDefaultRunLoopMode];
while (weakSelf && !weakSelf.isStopped) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
NSLog(@"-- end -- %@", [NSThread currentThread]);
}];
[self.thread start];
}
return self;
}
- (void)dealloc {
NSLog(@"%s", __func__);
[self performSelector:@selector(__stop) onThread:self.thread withObject:nil waitUntilDone:YES];
}
- (void)executeTask:(void (^)(void))task {
if (!self.thread) return;
[self performSelector:@selector(__executeTask:) onThread:self.thread withObject:task waitUntilDone:NO];
}
- (void)__stop {
if (!self.thread) return;
self.stopped = NO;
CFRunLoopStop(CFRunLoopGetCurrent());
self.thread = nil;
}
- (void)__executeTask:(void (^)(void))task {
task();
}
如果需要使用就只需要创建一个 YXCPermanentThread
实例对象,把需要的操作通过 executeTask:
方法传入进去,然后其他的都不需要再操作了。当然也可以在.h
文件中添加一个停止的方法,对RunLoop
进行停止操作。
网友评论