显示 UIAlert 会使应用程序崩溃吗?
display UIAlert will crash the app on present?
我有一个测试连接操作逻辑。它将实时或不实时测试服务器。当逻辑完成测试并尝试在闭包线程内显示 UIAlertController 时会发生错误,这会使系统崩溃。
@IBAction func TestNetwork(_ sender: Any) {
var message = "\(internetConnection) internet connection \n \(serverStatus) server\n "
self.showSpinner(onView: self.view)
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
self.testConnection(connectionTestCompletionHanlder: {connectionResult in
let alertController = UIAlertController(title: "Alert", message: message, preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .default) { (action) in
// Respond to user selection of the action.
}
alertController.addAction(defaultAction)
//self.removeSpinner()
self.present(alertController, animated: true){
// The alert was presented
}
})
}
}
错误
-[Assert] Cannot be called with asCopy = NO on non-main thread.
+[UIView setAnimationsEnabled:] being called from a background thread. Performing any operation from a background thread on UIView or a
subclass is not supported and may result in unexpected and insidious
behavior.
-Unsupported use of UIKit view-customization API off the main thread. -setHasDimmingView: sent to <_UIAlertControllerView: 0x7ffe2ff8b4a0; frame = (0 0; 375 667); layer = >
-Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Modifications to the
layout engine must not be performed from a background thread after it
has been accessed from the main thread.'
根据上面的评论,您应该始终在主线程上启动 UI 工作。上面的完成处理程序虽然通过 asyncAfter
在主线程上实例化,但可以在任何线程上执行,因此您需要更改打开警报控制器的部分以明确在主线程上:
//previous code as above...
DispatchQueue.main.async {
self.present(alertController, animated: true){
// The alert was present
}
}
如果您不打算使用它,您也可以将警报控制器的完成处理程序设置为 nil,而不是空闭包。
我遇到了类似的问题。别人遇到的就在这里回答。
应用程序也可能在 iOS 13.3(至少)中崩溃,当显示请求权限的警报时,当您的应用程序使用 SceneDelegate 时,即使 Application Scene Manifest 条目存在于 plist 文件中。
不得不从 info.plist 文件中删除 SceneDelegate 和相关条目,并且不再崩溃。
我有一个测试连接操作逻辑。它将实时或不实时测试服务器。当逻辑完成测试并尝试在闭包线程内显示 UIAlertController 时会发生错误,这会使系统崩溃。
@IBAction func TestNetwork(_ sender: Any) {
var message = "\(internetConnection) internet connection \n \(serverStatus) server\n "
self.showSpinner(onView: self.view)
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
self.testConnection(connectionTestCompletionHanlder: {connectionResult in
let alertController = UIAlertController(title: "Alert", message: message, preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .default) { (action) in
// Respond to user selection of the action.
}
alertController.addAction(defaultAction)
//self.removeSpinner()
self.present(alertController, animated: true){
// The alert was presented
}
})
}
}
错误
-[Assert] Cannot be called with asCopy = NO on non-main thread. +[UIView setAnimationsEnabled:] being called from a background thread. Performing any operation from a background thread on UIView or a subclass is not supported and may result in unexpected and insidious behavior.
-Unsupported use of UIKit view-customization API off the main thread. -setHasDimmingView: sent to <_UIAlertControllerView: 0x7ffe2ff8b4a0; frame = (0 0; 375 667); layer = >-Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Modifications to the layout engine must not be performed from a background thread after it has been accessed from the main thread.'
根据上面的评论,您应该始终在主线程上启动 UI 工作。上面的完成处理程序虽然通过 asyncAfter
在主线程上实例化,但可以在任何线程上执行,因此您需要更改打开警报控制器的部分以明确在主线程上:
//previous code as above...
DispatchQueue.main.async {
self.present(alertController, animated: true){
// The alert was present
}
}
如果您不打算使用它,您也可以将警报控制器的完成处理程序设置为 nil,而不是空闭包。
我遇到了类似的问题。别人遇到的就在这里回答。
应用程序也可能在 iOS 13.3(至少)中崩溃,当显示请求权限的警报时,当您的应用程序使用 SceneDelegate 时,即使 Application Scene Manifest 条目存在于 plist 文件中。 不得不从 info.plist 文件中删除 SceneDelegate 和相关条目,并且不再崩溃。