嵌套 DispatchQueue.main.async
Nested DispatchQueue.main.async
我在从 VC 调用的函数中显示警报。我不希望 main VC 被阻止。我正在异步调用此警报功能。该函数又具有另一个异步。这是好的做法还是我做错了?
任何人都可以建议以下代码的良好做法吗?
class MyVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Don't block main thread
DispatchQueue.main.async {
self.showAlert(title: "Title", message: "Message")
}
// Do other stuff ...
}
}
func showAlert(title: String = "", message: String) {
alert = UIAlertController(title: title,message: message, preferredStyle: .alert)
let cancelAction = UIAlertAction(title: "Ok", style: .cancel, handler: nil)
alert.addAction(cancelAction)
DispatchQueue.main.async {
UIApplication.shared.keyWindow?.rootViewController!.present(alert, animated: true, completion: nil)
}
}
显示警报不会阻塞线程。 present(_:animated:completion:)
不是阻塞操作,因此没有理由添加任何这些 .async
调用。
就是说,您不想尝试在 viewDidLoad
中显示警报。那还为时过早。你的视图控制器还没有出现在屏幕上。您应该将 showAlert()
放入 viewDidAppear
,并删除所有 .async
调用。
作为一般规则,这些类型的模态警报在任何情况下都应该是最后的手段,尤其是当视图控制器出现在屏幕上时。通常,您应该将要呈现给用户的任何消息集成到视图本身,而不是阻塞整个 UI。但是如果警报是适当的(有时是),那么只要您在主队列中就可以直接显示它们。
你应该只把你必须的东西放在主线程上。所以你不应该把它包装在 viewDidLoad 函数的 main.async 块中。
您应该将其包装在具有不同优先级的 DispatchQueue
中。
即DispatchQueue.global(qos: .userInitiated).async { }
您似乎对 DispatchQueue
有疑问:)
您的程序在 运行 时使用操作队列。此队列可以是系统定义的(如 main
)或用户定义的。当您使用 DispatchQueue.main.async(_:)
时,您将代码块排入主队列。当他们的时间到了,主队列执行他们。
但是在 viewDidLoad(_:)
中,您已经在 main
队列中了。此外,调用 AlertController
的原因是 UI 操作,并且 UI 操作不能在除 main
之外的任何队列上完成,您不需要发送代码阻止任何队列,你不应该。
而且,正如@SeanRobinson159 所说,AlertController
在屏幕上时不会阻塞主线程。它与您的其他 ViewControllers
.
一样工作
那么,在哪些情况下你应该使用DispatchQueue
来调用AlertController
您应该使用 DispatchQueue.main.async(_:)
将执行 UI 操作(例如调用 AlertController
或更改 UILabel
的文本)的代码块从不同的队列发送到主队列队列。例如,您可能从事网络运营工作。您在不同的线程中进行操作,当结果出现时,您可以将进行 UI 操作的代码块发送到主队列。
您可以google GCD(Grand Central Dispatch) 获取详细信息。
我在从 VC 调用的函数中显示警报。我不希望 main VC 被阻止。我正在异步调用此警报功能。该函数又具有另一个异步。这是好的做法还是我做错了?
任何人都可以建议以下代码的良好做法吗?
class MyVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Don't block main thread
DispatchQueue.main.async {
self.showAlert(title: "Title", message: "Message")
}
// Do other stuff ...
}
}
func showAlert(title: String = "", message: String) {
alert = UIAlertController(title: title,message: message, preferredStyle: .alert)
let cancelAction = UIAlertAction(title: "Ok", style: .cancel, handler: nil)
alert.addAction(cancelAction)
DispatchQueue.main.async {
UIApplication.shared.keyWindow?.rootViewController!.present(alert, animated: true, completion: nil)
}
}
显示警报不会阻塞线程。 present(_:animated:completion:)
不是阻塞操作,因此没有理由添加任何这些 .async
调用。
就是说,您不想尝试在 viewDidLoad
中显示警报。那还为时过早。你的视图控制器还没有出现在屏幕上。您应该将 showAlert()
放入 viewDidAppear
,并删除所有 .async
调用。
作为一般规则,这些类型的模态警报在任何情况下都应该是最后的手段,尤其是当视图控制器出现在屏幕上时。通常,您应该将要呈现给用户的任何消息集成到视图本身,而不是阻塞整个 UI。但是如果警报是适当的(有时是),那么只要您在主队列中就可以直接显示它们。
你应该只把你必须的东西放在主线程上。所以你不应该把它包装在 viewDidLoad 函数的 main.async 块中。
您应该将其包装在具有不同优先级的 DispatchQueue
中。
即DispatchQueue.global(qos: .userInitiated).async { }
您似乎对 DispatchQueue
有疑问:)
您的程序在 运行 时使用操作队列。此队列可以是系统定义的(如 main
)或用户定义的。当您使用 DispatchQueue.main.async(_:)
时,您将代码块排入主队列。当他们的时间到了,主队列执行他们。
但是在 viewDidLoad(_:)
中,您已经在 main
队列中了。此外,调用 AlertController
的原因是 UI 操作,并且 UI 操作不能在除 main
之外的任何队列上完成,您不需要发送代码阻止任何队列,你不应该。
而且,正如@SeanRobinson159 所说,AlertController
在屏幕上时不会阻塞主线程。它与您的其他 ViewControllers
.
那么,在哪些情况下你应该使用DispatchQueue
来调用AlertController
您应该使用 DispatchQueue.main.async(_:)
将执行 UI 操作(例如调用 AlertController
或更改 UILabel
的文本)的代码块从不同的队列发送到主队列队列。例如,您可能从事网络运营工作。您在不同的线程中进行操作,当结果出现时,您可以将进行 UI 操作的代码块发送到主队列。
您可以google GCD(Grand Central Dispatch) 获取详细信息。