Run Loop是同步还是异步?为何我的代码未出现预期死锁?
为什么这段Objective-C代码未出现预期死锁?
问题代码
- (void)viewDidLoad { [super viewDidLoad]; __block BOOL completed = NO; [self doMyWork:^{ completed = YES; }]; while (!completed) { [NSRunLoop.currentRunLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]]; } }
核心疑问
原本判断这段代码会形成死锁:completion block在主线程运行,需viewDidLoad返回才能执行;而viewDidLoad要返回,又依赖completion block触发completed标志,形成循环等待。但实际运行未出现死锁,哪里理解有误?
原因解析
问题出在对NSRunLoop工作机制的误解:
- 当调用
[NSRunLoop.currentRunLoop runUntilDate:]时,主线程的RunLoop会进入一个临时的处理周期,在这个周期内它会处理当前主线程队列中已等待的所有事件,包括待执行的block。 - 如果
doMyWork:是将completion block异步派发到主线程队列(比如通过dispatch_async),那么在RunLoop临时运行的过程中,这个block会被执行,completed被设为YES,循环随即终止,不会出现死锁。 - 即使
doMyWork:是同步执行completion block,completed会被立刻赋值为YES,while循环根本不会启动,自然也不会产生死锁。
只有当completion block必须等到viewDidLoad执行完毕后,RunLoop进入下一轮自然循环才会执行,同时viewDidLoad又卡在等待block执行时,才会触发死锁。但你的代码通过手动调用RunLoop,主动触发了事件处理,打破了这个循环等待的条件。
内容的提问来源于stack exchange,提问作者OMGPOP
相关产品推荐
相关产品推荐

