从后台线程调用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:
这样就没有问题了。 如果我们已经将它调到主要位置,那么这个调用不应该导致任何明显的减速,但如果从后台线程调用它,我可以轻松地知道它的安全性。