iOS Runloop 线程保活及坑

作者: 孙掌门 | 来源:发表于2020-02-19 16:25 被阅读0次

iOS Runloop 线程保活及坑

Thread *th = [[Thread alloc] initWithTarget:self selector:@selector(testThread) object:nil];
    [th start];
    
    - (void)testThread{
    NSLog(@"test thread");
}
    
@implementation Thread
-(void)dealloc{
    NSLog(@"NSThread dealoc");
}
@end

上面的代码, Thread 这个类继承自 NSThread ,然后重写了 dealloc 方法,目的是为了看一下这个类是否在执行完任务后被释放,我们看下打印。

2020-02-19 16:05:51.150818+0800 blogTest[7713:410122] test thread
2020-02-19 16:05:51.151482+0800 blogTest[7713:410122] NSThread dealoc

从打印结果可以看出,我们的 thread 在执行完testThread 方法之后就 dealloc 了,那我们现在要做的就是让这个线程保活,不让他 dealloc。

我们的目的是让这个线程,有事做的时候活跃起来,没有事做的时候就休眠

- (void)testThread{
    NSLog(@"test thread");
    // 向runloop里面添加事件source/timer/observer
    [[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
    [[NSRunLoop currentRunLoop] run];
}

我们将代码改成这样之后,发现没有调用 dealloc,也就是说我们达到了保活的效果了,当我们这个线程在执行完啊这个方法的时候就开始保活休眠睡觉了。

那我们测试下,这个线程是否一直保活。

- (void)testThread{
    NSLog(@"test thread");
    // 向runloop里面添加事件source/timer/observer
    [[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
    [[NSRunLoop currentRunLoop] run];
}
- (void)testAnother{
    NSLog(@"test another");
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    [self performSelector:@selector(testAnother) onThread:_thread withObject:nil waitUntilDone:NO];
}

上面的代码意思就是,当我们点击屏幕的时候,就在这个子线程里面去执行任务,我们测试一下发现,每次都会打印

2020-02-19 16:22:25.217538+0800 blogTest[7806:425090] test thread
2020-02-19 16:22:26.498719+0800 blogTest[7806:425090] test another
2020-02-19 16:22:26.825388+0800 blogTest[7806:425090] test another
2020-02-19 16:22:27.056183+0800 blogTest[7806:425090] test another
2020-02-19 16:22:27.247697+0800 blogTest[7806:425090] test another
2020-02-19 16:22:27.439158+0800 blogTest[7806:425090] test another
2020-02-19 16:22:27.598440+0800 blogTest[7806:425090] test another
2020-02-19 16:22:27.757769+0800 blogTest[7806:425090] test another
2020-02-19 16:22:27.901013+0800 blogTest[7806:425090] test another


当我们将 保活的代码去掉试一下,发现就会打印一下,说明线程在执行完任务之后就死掉了。

所以当我们想在一个线程里面多次执行任务,还不想一直创建和销毁线程的时候,就可以选择线程保活的思想,将这个线程一直保活供我们使用。

销毁线程

上面的线程其实是一直在 run,虽然没有事情做,但是是一直存在的,没有销毁。我们需要改下代码


- (void)stop{
    CFRunLoopStop(CFRunLoopGetCurrent());
}
- (void)stopRunloop{
    [self performSelector:@selector(stop) onThread:_thread withObject:nil waitUntilDone:NO];
}

当我们需要停止到我们的runloop的时候,就手动调用 stopRunloop 方法就可以,这个方法会在当前这个保活线程去调用stop方法,我们的stop方法的意思是停止掉当前线程,这样就做到了我们的需求。

其实上面是停止不了的,run 方法,内部会一直不断的调用 [[NSRunLoop currentRunLoop] runMode:<#(nonnull NSRunLoopMode)#> beforeDate:<#(nonnull NSDate *)#>]; 这个方法啊,就好比,

while (1) {
            [[NSRunLoop currentRunLoop] runMode:<#(nonnull NSRunLoopMode)#> beforeDate:<#(nonnull NSDate *)#>];

    }

这样,我们只是停止了一次runmode,而 run方法内部其实会一直不断的执行,所以需要我们修改下代码


- (void)stop{
    _stop = YES;
    CFRunLoopStop(CFRunLoopGetCurrent());
}
- (void)stopRunloop{
    [self performSelector:@selector(stop) onThread:_thread withObject:nil waitUntilDone:NO];
}
- (void)testThread{
    NSLog(@"test thread");
    // 向runloop里面添加事件source/timer/observer
    [[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
    while (!_stop) {
            [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];

    }
}

我们保活的代码,通过一个变量来控制,当我们需要停止的时候,就不会再继续run了,严谨点的话我们还需要在用到 ——thread 的前面都要加上判断,判断_thread还是否存在,在stop的时候要讲_thread给置为nil,然后while的时候要判断weakself是否存在。

相关文章

  • iOS Runloop 线程保活及坑

    iOS Runloop 线程保活及坑 上面的代码, Thread 这个类继承自 NSThread ,然后重写了 d...

  • iOS底层原理——浅谈RunLoop

    RunLoop应用:线程保活 线程保活、控制销毁 iOS-浅谈RunLoop8iOS底层原理总结 - RunLoo...

  • iOS Runloop的理解与使用

    Runloop的概念 Runloop的存在主要就是为了线程保活,线程保活是为了线程能够及时的处理事件,不会在其执行...

  • iOS笔记-runloop

    runloop可以做什么? 处理crash 保持线程存活(线程保活) 监测、优化卡顿 线程和runloop有什么关...

  • RunLoop 02 - 应用(线程保活)

    RunLoop 02 - 应用(线程保活) PermanentThread PermanentThread 使用示例

  • RunLoop学习笔记

    参考深入理解RunLoop深入研究 Runloop 与线程保活RunLoop分享by孙源 RunLoop的概念 R...

  • Runloop源码解析:运行逻辑

    Runloop应用: Timer失效问题; 线程保活; Runloop的运行逻辑: 入口函数 通知Observer...

  • 10.3 runloop 的实际应用

    runloop实际中的应用 控制线程生命周期(线程保活)、崩溃的起死回生 runloop和performselec...

  • iOS总结篇-RunLoop

    RunLoop是什么? RunLoop是一个事件循环,让线程休眠和线程保活成为了可能,线程休眠可以节省CPU资源;...

  • Runloop学习资料整理

    基于runloop的线程保活、销毁与通信 深入理解RunLoop developer.apple.com/libr...

网友评论

    本文标题:iOS Runloop 线程保活及坑

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