9

iOS 的 UIKit 不是线程安全的,让我们称之为众所周知的事实。我知道规则,我很小心,但我仍然会被咬 - 而且时不时地导致的崩溃与对 UIKit 的令人讨厌的后台调用相距甚远,从而使追踪问题成为一种不那么愉快的体验。

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

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

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


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

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

UIView 的 viewDidLoad 方法在 Xcode 中内联产生运行时警告UIView.frame 必须仅从主线程使用,并且将一条消息打印到控制台:主线程检查器:在后台线程上调用 UI API:-[UIView 框架]

4

3 回答 3

3

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

我刚刚用它来处理我刚刚获取的一些代码中的许多 UIKit/主线程问题。

于 2013-09-12T13:54:29.400 回答
1

我尽量不引入多线程,除非我首先尝试了单线程方法,但这取决于您要解决的问题。

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

只是我的观点。

编辑

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

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];
于 2012-12-10T18:19:54.137 回答
0

就个人而言,每当我打开多线程方法的盒子时,我都会开始包装所有基于接口的调用,performSelectorOnMainThread:这样就不会出现问题。如果我们已经进入主线程,那么这个调用应该不会导致任何明显的减速,但是如果它是从后台线程调用的,我可以放心地知道它是安全的。

于 2012-12-10T18:55:06.807 回答