NSRunLoop之线程保活

什么是线程保活?

线程不死(线程处于激活状态,而不是NSThread实例对象被销毁),可以在同一个线程中做多件事,而且想什么时候做什么时候做。

我们以NSThread这个类来探讨线程保活的问题。看代码:

  - (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor = [UIColor yellowColor];

self.thread = [[LSThread alloc] initWithTarget:self selector:@selector(start) object:nil];
[self.thread start];
}

- (void)start{
NSLog(@"线程1开启做的第一件事...");
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[self performSelector:@selector(doSth) onThread:self.thread withObject:nil waitUntilDone:NO];
}
- (void)doSth{
NSLog(@"在线程1中继续做其他事...");
}

其中的LSThread是继承自NSThread的。
当点击屏幕的时候,能在子线程self.thread中执行doSth方法吗?
通过代码,得到的答案是不能。这是为什么呢?因为子线程在执行完start方法之后就销毁了,所以不能再在该子线程中执行其他方法。为了让doSth方法执行,所以我们要让该子线程保活。

NSRunLoop保活线程

修改代码:

  - (void)start{
NSLog(@"线程1开启做的第一件事...");
NSLog(@"线程1开启做的第一件事...");
NSLog(@"线程开始");
[[NSRunLoop currentRunLoop] addPort:[[NSPort alloc] init] forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] run];
NSLog(@"线程结束");
}

一个线程对应一个RunLoop,我们在子线程的RunLoop添加一个source1即NSPort对象,并跑在默认模式下,且时间是无限的,这样线程就能一直存在。
看打印:

2020-01-19 18:47:51.190543+0800 69.线程保活[8095:663010] 线程1开启做的第一件事...
2020-01-19 18:47:51.190933+0800 69.线程保活[8095:663010] 线程开始
2020-01-19 18:47:54.763623+0800 69.线程保活[8095:663010] 在线程1中继续做其他事...

线程保活的目的达到了,但这样的写法还有问题。

循环引用的问题

当我们退出当前控制器的时候,控制器LSThread对象没有被销毁,当前控制器也没有被销毁,这是因为两者发生了循环引用。
产生循环引用的代码:

  self.thread = [[LSThread alloc] initWithTarget:self selector:@selector(start) object:nil];

我们可以联想以下NSTimer的类似创建方法,这样的创建实例的方法会让实例对target产生强引用。

解决循环引用

更改创建LSThread对象的方法,使用block

  self.thread = [[LSThread alloc] initWithBlock:^{
     NSLog(@"线程1开启做的第一件事...");
     NSLog(@"线程1开启做的第一件事...");
     NSLog(@"线程开始");
     [[NSRunLoop currentRunLoop] addPort:[[NSPort alloc] init] forMode:NSDefaultRunLoopMode];
     [[NSRunLoop currentRunLoop] run];
     NSLog(@"线程结束");
 }];

我们把让线程保活的代码同样方法block中。
这样就解决了循环引用的问题,在退出当前控制器的时候,控制器也会被销毁,但此时我们使用的LSThread对象仍然不能被销毁,这个问题留到下篇文章解决。

你可能感兴趣的:(NSRunLoop之线程保活)