从后台线程调用UIKit时发出警告

iOS的UIKit不是线程安全的,让我们称之为众所周知的事实。 我知道这个规则,我很小心,但我仍然被咬了 – 而且偶尔会因为违规背景调用UIKit而导致崩溃,这使得追踪问题的能力低于欢乐体验。

这个问题似乎很容易解决 – 让UIKit类/方法在从后台线程调用时发出警告,至少作为调试function。 据我所知,iOS不提供任何此类function。 当然,通过在这样的调用之前使用某种forms的断言可以手动实现相同的效果,但是这种解决方案不是最优雅的,并且还存在与原始问题相同的弱点,即程序员易于忘记。

有没有人有更优雅的解决方案? 你如何处理项目中的这个问题?

(注意: 这个问题是相关的,但不是那么明确。一个人想知道)


更新 :安德鲁的答案是我当时正在寻找的解决方案,但请注意,至少从Xcode 9开始,这是由xcode / ios提供的。 例如,添加以下代码:

DispatchQueue.global().async { print(self.view.frame) } 

UIView的viewDidLoad方法在Xcode中生成运行时警告UIView.frame必须仅在主线程中使用,并且消息打印到控制台: 主线程检查器:在后台线程上调用的UI API: – [UIView frame]

此代码(仅添加到项目并在没有ARC的情况下编译此文件)会导致在主线程之外的UIKit访问断言: https : //gist.github.com/steipete/5664345

我刚用它来拾取我刚收到的一些代码中的大量UIKit /主线程问题。

我尝试不引入multithreading,除非我先尝试过单线程方法,但这取决于你试图解决的问题。

即使multithreading是唯一的选择,我通常也会避免长时间运行后台操作或执行多个不相关任务的操作。

只是我的观点。

编辑

在显示加载微调器的同时在主线程上进行工作的示例:

 MBProgressHUD *hud = [MBProgressHUD customProgressHUDInView:view dim:dim]; [hud show:NO]; //Queue it so the ui has time to show the loading screen before the op starts NSBlockOperation *blockOp = [NSBlockOperation blockOperationWithBlock:block]; NSBlockOperation *finOp = [NSBlockOperation blockOperationWithBlock:^{ [MBProgressHUD hideAllHUDsForView:view animated:NO]; }]; [finOp addDependency:blockOp]; [[NSOperationQueue mainQueue] addOperations:@[blockOp, finOp] waitUntilFinished:NO]; 

我个人随时打开multithreading方法的盒子,我开始在performSelectorOnMainThread:包装所有基于接口的调用performSelectorOnMainThread:这样就没有问题了。 如果我们已经将它调到主要位置,那么这个调用不应该导致任何明显的减速,但如果从后台线程调用它,我可以轻松地知道它的安全性。