美文网首页iOS开发技巧
NSRunLoop之线程保活

NSRunLoop之线程保活

作者: 梁森的简书 | 来源:发表于2020-01-22 21:58 被阅读0次

    什么是线程保活?

    线程不死(线程处于激活状态,而不是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<UITouch *> *)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之线程保活

        本文链接:https://www.haomeiwen.com/subject/azchzctx.html