我正在尝试实现类似于Javascript / C#的async / await的功能。我正在尝试使用信号量,并在我的XCode Playground中发现它可与URLSession一起使用。
因此,我现在尝试使用以下代码对Firebase身份验证执行相同的操作:
var response:String? = "test"
let semaphore = DispatchSemaphore(value: 0)
Auth.auth().createUser(withEmail: email, password: password) { (result, err) in
if err != nil {
response = "\(String(describing: err))"
}else{
response = nil
}
semaphore.signal()
}
let _ = semaphore.wait()
if response == nil{
self.transitionToHome()
}
但是,模拟器永远冻结,似乎从未调用过semaphore.signal()
。也没有出现将打印语句放置在semaphore.signal()
附近的情况。我还将Firestore代码放置在DispatchQueue.global(qos: .background).async
中,随后尝试在DispatchQueue.main.async
中检索响应值,但响应也未得到更新。下面的代码反映了我的所作所为:
DispatchQueue.global(qos: .background).async {
Auth.auth().createUser(withEmail: email, password: password) { (result, err) in
if err != nil {
response = "\(String(describing: err))"
}else{
response = nil
}
semaphore.signal()
}
let _ = semaphore.wait()
}
if response == nil{
self.transitionToHome()
}
虽然这没有冻结UI,但是在调用DispatchQueue
之后没有获得响应值。我也在if-else
块中调用了DispatchQueue.main.async
块,但结果也相同。
此外,在等待一段时间后,我看到此错误在我的xcode终端中弹出:
020-01-02 01:33:25.447842+0800 das-carddeckapp[78136:10508853] Connection 4: received failure notification
2020-01-02 01:33:25.448179+0800 das-carddeckapp[78136:10508853] Connection 4: failed to connect 1:50, reason -1
2020-01-02 01:33:25.448387+0800 das-carddeckapp[78136:10508853] Connection 4: encountered error(1:50)
2020-01-02 01:33:25.457587+0800 das-carddeckapp[78136:10508853] Task <3A3720D6-7549-4C31-96A2-C88B89294821>.<1> HTTP load failed, 0/0 bytes (error code: -1009 [1:50])
我知道使用完成处理程序会使这项工作完成,但是我想在诉诸完成处理程序之前尝试使其工作。非常感谢您的帮助!
[第一个示例(您在主线程上调用wait
的地方是死锁”,因为它用wait
阻塞了主线程,这要从createUser
闭包中发出,这也希望在主线程(已阻止)上运行。结果是程序化的“ Catch-22”。
我知道信号量被认为是一种不好的模式,但是我只是想了解为什么它不起作用。
您的第二个示例,在其中将wait
分派到全局队列的情况解决了死锁。但是,由于您是异步调度的,因此这意味着主线程将在全局队列等待响应时继续进行。结果,几乎可以保证您没有准备返回的值。
总之,您不能轻易让主队列都等待异步方法在主队列上调用其完成处理程序。
但是将其放在一边,如果这是一个iOS应用程序,曾经阻塞主线程只是一个严重的问题(即使您可以解决死锁)。应用冻结时,这是一个可怕的用户体验。如果不幸的移动用户发现自己的蜂窝连接不佳,这可能会导致不小的延迟,则尤其如此。更糟糕的是,如果您不幸在错误的时间阻止主线程,则iOS看门狗进程可能会毫不客气地杀死您的应用程序。
嘿,我明白了。我们都去过那里。当我们第一次遇到异步编程模式(如网络请求)时,如果我们只等待响应,就会感觉更加逻辑和直观。但应不惜一切代价避免这种情况。如果您坚持采用公认的异步编程模式,而不是与之抗争,那么从长远来看,您会更加快乐。