2025-02-08 12:14:18
,某些文章具有时效性,若有错误或已失效,请在下方留言。If you want to read the return value from a Task
directly, you should read its value
using await
, or use try await
if it has a throwing operation. However, all tasks also have a result
property that returns an instance of Swift’s Result
struct, generic over the type returned by the task as well as whether it might contain an error or not.
如果要直接从 Task
读取返回值,则应使用 await
读取其值
,如果它具有 throwing作,则应使用 try await
。但是,所有任务也都有一个 result
属性,该属性返回 Swift 的 Result
结构体的实例,该实例在任务返回的类型上泛型,以及它是否可能包含错误。
To demonstrate this, we could write some code that creates a task to fetch and decode a string from a URL. To start with we’re going to make this task throw errors if the download fails, or if the data can’t be converted to a string.
为了演示这一点,我们可以编写一些代码来创建一个任务,从 URL 获取和解码字符串。首先,如果下载失败,或者数据无法转换为字符串,我们将使此任务引发错误。
Here’s the code: 这是代码:
enum LoadError: Error {
case fetchFailed, decodeFailed
}
func fetchQuotes() async {
let downloadTask = Task {
let url = URL(string: "https://hws.dev/quotes.txt")!
do {
let (data, _) = try await URLSession.shared.data(from: url)
if let string = String(data: data, encoding: .utf8) {
return string
} else {
throw LoadError.decodeFailed
}
} catch {
throw LoadError.fetchFailed
}
}
let result = await downloadTask.result
do {
let string = try result.get()
print(string)
} catch LoadError.fetchFailed {
print("Unable to fetch the quotes.")
} catch LoadError.decodeFailed {
print("Unable to convert quotes to text.")
} catch {
print("Unknown error.")
}
}
await fetchQuotes()
There’s not a lot of code there, but there are a few things I want to point out as being important:
那里的代码并不多,但我想指出一些很重要的事项:
- Our task might return a string, but also might throw one of two errors. So, when we ask for its
result
property we’ll be given aResult<String, Error>
.
我们的任务可能会返回一个字符串,但也可能会引发两个错误之一。因此,当我们请求其result
属性时,我们将得到Result<String, Error>
。 - Although we need to use
await
to get the result, we don’t need to usetry
even though there could be errors there. This is because we’re just reading out the result, not trying to read the successful value.
虽然我们需要使用await
来获取结果,但我们不需要使用try
,即使那里可能存在错误。这是因为我们只读出结果,而不是尝试读取 successful 值。 - We call
get()
on theResult
object to read the successful value inside, but that’s whentry
is needed because it’s when Swift checks whether an error occurred or not.
我们在Result
对象上调用get()
来读取里面的 successful 值,但这时 需要try
,因为这是 Swift 检查是否发生错误的时候。 - In Swift 6.0 and later we can use
throws(LoadError)
in our task’s closure to make it clear this only throws one specific error type, but at the time of writing Swift doesn’t supported typed errors in tasks so it doesn’t help much.
在 Swift 6.0 及更高版本中,我们可以在任务的闭包中使用throws(LoadError)
来明确这只抛出一种特定的错误类型,但在编写时,Swift 不支持在任务中输入错误,因此没有多大帮助。
If you don’t care what errors are thrown, or don’t mind digging through Foundation’s various errors yourself, you can avoid handling errors in the task and just let them propagate up:
如果你不在乎抛出什么错误,或者不介意自己深入研究 Foundation 的各种错误,你可以避免处理任务中的错误,让它们向上传播:
func fetchQuotes() async {
let downloadTask = Task {
let url = URL(string: "https://hws.dev/quotes.txt")!
let (data, _) = try await URLSession.shared.data(from: url)
return String(decoding: data, as: UTF8.self)
}
let result = await downloadTask.result
do {
let string = try result.get()
print(string)
} catch {
print("Unknown error.")
}
}
await fetchQuotes()
The main take aways here are:
这里的主要收获是:
- All tasks can return a
Result
if you want.
如果需要,所有任务都可以返回Result
。 - For the error type, the
Result
will either containError
orNever
.
对于 error 类型,Result
将包含Error
或Never
。 - Although we need to use
await
to get the result, we don’t need to usetry
until we try to get the success value inside.
虽然我们需要使用await
来获取结果,但我们不需要使用try
,直到我们尝试获取里面的 success 值。
Many places where Result
was useful are now better served through async/await, but Result
is still useful for storing in a single value the success or failure of some operation. Yes, in the code above we evaluate the result immediately for brevity, but the power of Result
is that it’s a value you can pass around elsewhere in your code to deal with at a later time.Result
的许多有用地方现在通过 async/await 更好地提供服务,但 Result
对于将某些作的成功或失败存储在单个值中仍然很有用。是的,为了简洁起见,在上面的代码中,我们会立即评估结果,但 Result
的强大之处在于,它是一个值,你可以在代码中的其他位置传递,以便稍后处理。