-[UIApplication delegate] 只能从主线程调用

60

这个警告导致了一个严重的问题,因为我在使用 Xcode 9 beta 2 时无法在主线程之外调用代理。奇怪的是,在使用 Xcode 8.3.3 时,这个功能是有效的。

而且我认为只从主线程调用代理是良好的实践,不是吗?那么为什么现在会导致应用程序崩溃呢?


1
显然你是从另一个线程中执行的。如果你不分享一些代码,我们无法帮助你。 - phi
3
仅因代码“可行”并不意味着它是正确的。在线程问题上,它可能会“适用”于9999/10000次,但最后一个失败通常会发生在审核人员手中。 ;) - bbum
还要检查堆栈跟踪,确保是你的代码而不是第三方库。 - Artem Abramov
2个回答

89

只需要在主线程中像这样调用它。

Objective-C

dispatch_async(dispatch_get_main_queue(), ^{
  [[UIApplication delegate] fooBar];
});

Swift

DispatchQueue.main.async {
  YourUIControlMethod()
}

像这样联系你的应用程序代理表明你的架构可能需要进行一些清理。

您可以从任何线程调用委托。您只需要确保在UIKit的主线程上进行调用。 或者您在CoreData对象期望的正确线程上。这完全取决于您的对象具有的API合同。


只是想知道您所说的“架构清理”具体指什么。例如,假设我有一个对CoreData使用的当前上下文的引用。我通过我的AppDelegate访问它。那我应该把它放在哪里呢? - el-flor
2
你可以创建一个单独的对象来包装你所有的CoreData代码。然后将该对象传递到需要它们的视图控制器中(依赖注入)。 - orkoden
5
这里提到的“架构清理”指的是你几乎不应该在代码中引用 [[UIApplication sharedApplication] delegate]。应用程序代理是 UIApplication 的代理,而不是全局存储的临时场所。如果您想要一个单例来保存您正在保存的内容,请创建一个新的单例。您的应用程序代理代码通常应该很短,并且只关注应用程序状态转换,而不是存储模型。 - Rob Napier
1
“但是应用代理是最接近CPU的东西!”(这是一个玩笑,未来不确定iOS的读者) - royalmurder

25

在 Swift 中,您还可以使用 DispatchQueue.main.async 从主线程调用 UI 控制方法。

DispatchQueue.main.async {
    YourUIControlMethod()
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接