登录管理器正在非主线程上运行您的闭包,因此您不能在主线程之外使用用户界面元素。
其他人已经说过,在辅助线程上仅读取UI属性是可以的,他们可能是正确的,但是没有绝对的保证,个人而言,我会遵循警告。例如,访问这些属性可能会有副作用。也许它们的值被缓存在某个地方,而主线程正在更新或删除该属性,恰好在你想访问它的时候。
消除警告的正确方法是在主线程上执行您的闭包,例如:
LoginManager.checkLoginStatus {
isLoggedIn in
DispatchQueue.main.async {
// Do all your UI stuff here
}
}
这种方式下,运行闭包的线程除了在主队列上安排代码运行之外什么都不做,而主队列始终在主线程上运行。
只需添加DispatchQueue.main.async即可防止此问题,而且这也是Swift文档推荐的方法。
DispatchQueue.main.async {
//code that caused error goes here
}
- Xcode 9 中新增的主线程检查器。
- 可检测来自后台线程的 UI API 不当使用。
- 可检测未在主线程上进行的 AppKit、UIKit 和 WebKit 方法调用。
- 在调试期间自动启用,可在方案编辑器的诊断选项卡中禁用。
- 主线程检查器可用于 Swift 和 C 语言。
尝试使用以下代码替换您的代码,并查看效果。这是一种永久性的解决方案,无需禁用警告。
@IBAction fund saveButtonTapped(_ sender: Any) {
LoginManager.checkLoginStatus { isLogged in
if isLogged {
// Updates your UIs on main queue
DispatchQueue.main.async(execute: {
if self.priceTextField.text == "" {
GlobalVariables.sharedManager.itemPrice = 0
} else {
GlobalVariables.sharedManager.itemPrice = Double(self.priceTextField.text!)!
}
if self.titleTextView.text == "" {
GlobalVariables.sharedManager.expenseTitle = "N/A"
} else {
GlobalVariables.sharedManager.expenseTitle = self.titleTextView.text!
}
if self.descriptionTextView.text == "" {
GlobalVariables.sharedManager.expenseDescription = "N/A"
} else {
GlobalVariables.sharedManager.expenseDescription = self.descriptionTextView.text!
}
if self.categoryPickerTextFld.text == "" {
GlobalVariables.sharedManager.expenseCategory = "N/A"
} else {
GlobalVariables.sharedManager.expenseCategory = self.categoryPickerTextFld.text!
}
if self.imageView.image == nil {
GlobalVariables.sharedManager.expenseSelectedImage = nil
} else {
GlobalVariables.sharedManager.expenseSelectedImage = self.imageView.image
}
})
}
}
}
问题的确在于您正在从后台线程使用UI元素。请尝试修改代码以便从主线程访问它们。
Xcode 9具有新功能-它可以在运行时检查此类问题并在执行期间报告它。
如果您真的不想要它,可以在方案设置中禁用它。编辑方案...->(选择您的方案)->诊断->禁用“主线程检查器”
if self.priceTextField.text == "" {
GlobalVariables.sharedManager.itemPrice = 0
}else{
GlobalVariables.sharedManager.itemPrice = Double(self.priceTextField.text!)!
}
} 我认为这可能行不通... - KirillCDispatchQueue.main.async
了吗?我认为这会起作用并且很有意义 - 在后台线程上执行一些耗时的操作(例如登录),然后回到主线程以更新UI。 - Anton Malmygin警告似乎过于激进,因为您仅检查textField是否为空,而不会更改UI上的任何内容。该警告试图阻止在主线程之外使用UI元素,这当然不是坏事,但它没有考虑到像您这样的边缘情况。