[[NSRunLoop currentRunLoop] run] 注意事项

总结:
一旦在子线程调用了 [[NSRunLoop currentRunLoop] run] 方法,那么在这个方法下的代码就永远无法执行到。若要继续往下执行代码,可使用 [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:seconds]] 方法代替。
参考文献:子线程上的RunLoop运行循环

Tip: @synchronized 的底层实现是使用了 recursive_mutex_t。

- (void)startTimer {
    self.timerThread = [[NSThread alloc] initWithTarget:self selector:@selector(createTimer) object:nil];
    [self.timerThread start];
}

// 加锁方式:在子线程上的启用RunLoop
- (void)createTimer {
//    方法一:该方法会死锁
    @synchronized (self) {
        if (self.heartbeatTimer) {
            [[NSRunLoop currentRunLoop] addTimer:self.heartbeatTimer forMode:NSRunLoopCommonModes];
            [[NSRunLoop currentRunLoop] run];
        }
    }
    
    NSRecursiveLock *recLock = [[NSRecursiveLock alloc] init];
//    方法二:该方法会死锁
    [recLock lock];
    if (self.heartbeatTimer) {
        [[NSRunLoop currentRunLoop] addTimer:self.heartbeatTimer forMode:NSRunLoopCommonModes];
        [[NSRunLoop currentRunLoop] run]; // 调用这个方法,会开启子线程的运行循环,不会停止,下面👇🏻的代码就始终执行不到了。
        // [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:60]]; // 调用这个方法,会开启子线程的运行循环,不会停止,直到 60s 后退出循环,在 60s 过后,下面👇🏻的代码才会执行。
        [recLock unlock];
    }
    
//    方法三:该方法不会死锁
    [recLock lock];
    if (self.heartbeatTimer) {
        [[NSRunLoop currentRunLoop] addTimer:self.heartbeatTimer forMode:NSRunLoopCommonModes];
        [recLock unlock]; // 在 [[NSRunLoop currentRunLoop] run] 方法前解锁,避免死锁。
        [[NSRunLoop currentRunLoop] run];
    }
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容