[英]how to properly throw and catch an error from swift async function
我有一个执行异步任务的 function。 有时该任务会失败并引发错误。 我无法从调用 function 中捕捉到该错误。下面的操场抓住了我遇到的问题的本质。
import UIKit
Task {
var newNum: Double = 99.9
do {
newNum = try await getMyNumber()
print("newNum within do: \(newNum)")
} catch MyErrors.BeingStupid { //never gets caught
print("caught being stupid")
} catch MyErrors.JustBecause { //does get caught if throw is uncommented
print("caught just because")
}
print("newNum outside of do \(newNum)")
}
print("done with main")
func getMyNumber() async throws -> Double {
let retNum:Double = 0
Task{
sleep(5)
let myNum: Double = Double.random(in: (0...10))
if myNum > 9 {
print("greater than 9")
} else {
print("less than 9 -- should throw")
throw MyErrors.BeingStupid // error doesn't get thrown? HOW DO I CATCH THIS?
}
}
// throw MyErrors.JustBecause // this *does* get caught if uncommented
return retNum //function always returns
}
enum MyErrors: Error {
case BeingStupid, JustBecause
}
我如何捕获在调用 function 时在注释为“HOW DO I CATCH THIS”的行中抛出的错误?
Task
用于非结构化并发。 如果目的是模拟异步任务,我会建议保持在结构化并发中。 因此,使用Task.sleep(nanoseconds:)
而不是sleep()
并消除getMyNumber
中的Task
:
func getMyNumber() async throws -> Double {
try await Task.sleep(nanoseconds: 5 * NSEC_PER_SEC) // better simulation of some asynchronous process
let myNum = Double.random(in: 0...10)
if myNum > 9 {
print("greater than 9")
} else {
print("less than 9 -- should throw")
throw MyErrors.beingStupid
}
return myNum
}
enum MyErrors: Error {
case beingStupid, justBecause
}
如果您保持在结构化并发中,抛出的错误很容易被捕获。
有关结构化和非结构化并发之间差异的更多信息,请参阅Swift 编程指南:并发或 WWDC 2021 视频Explore structured concurrency in Swift
上面说明了标准的结构化并发模式。 如果你真的必须使用非结构化并发,你可以try await
Task
,如果它没有抛出错误,返回它的value
,例如:
func getMyNumber() async throws -> Double {
let task = Task.detached {
sleep(5) // really bad idea ... never sleep ... especially never sleep on the main actor, which is why I used `Task.detached`
let myNum = Double.random(in: 0...10)
if myNum > 9 {
print("greater than 9")
} else {
print("less than 9 -- should throw")
throw MyErrors.beingStupid
}
return myNum
}
return try await task.value
}
请注意,因为我们正在运行一些缓慢且同步的东西,我们希望它在后台线程上运行,因此使用Task.detached
。
为了完整起见,我只包括这个非结构化并发示例。 您很可能希望保持结构化并发。 这样,您不仅可以享受更简洁的实现,还可以自动传播取消等。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.