我尝试使用 make @escaping 函数与
withUnsafeThrowingContinuation
进行异步/等待,但出现错误:
如果没有更多上下文,表达类型不明确
代码:
private func asyncUpload() async {
guard let image = self.manager?.getUserModel()?.image else { return }
let body = SetAvatarRequest(username: UserManager.shared.username, image: image)
do {
try await withUnsafeThrowingContinuation { (continuation: UnsafeContinuation<Void, Error>) in
RESTClient.shared.uploadImage(
fileName: "\(UserManager.shared.username)_avatar",
path: "files/avatar/\(UserManager.shared.userId)",
body: body) { result in
print(result)
switch result {
case .success:
UserManager.shared.setImage(image)
continuation.resume(returning: ())
self?.removeFromFailed(type: type)
case let .failure(error):
print("DEBUG: \(error.localizedDescription)")
continuation.resume(throwing: error)
}
}
} as Void
} catch {
print("error")
}
}
“如果没有更多上下文,表达式类型不明确”错误可能会产生误导,因为它只是告诉您它无法推理代码。在没有看到更多代码的情况下,并不完全清楚问题出在哪里,但是
self?.removeFromFailed(type: type)
非常可疑,因为 (a) 您传递给此函数的值 type
没有在任何地方定义; (b) 您没有 [weak self]
捕获列表,因此 self?
也没有意义。
当我删除该行后,错误就消失了。
private func asyncUpload() async throws {
guard let image = self.manager?.getUserModel()?.image else { return }
let body = SetAvatarRequest(username: UserManager.shared.username, image: image)
do {
try await withCheckedThrowingContinuation { continuation in
RESTClient.shared.uploadImage(
fileName: "\(UserManager.shared.username)_avatar",
path: "files/avatar/\(UserManager.shared.userId)",
body: body
) { result in
print(result)
switch result {
case .success:
UserManager.shared.setImage(image)
continuation.resume()
// self?.removeFromFailed(type: type)
case let .failure(error):
print("DEBUG: \(error)")
continuation.resume(throwing: error)
}
}
}
} catch {
print(error) // not print("error") … not even sure why you're printing it here given that you printed it above
throw error
}
}
现在,我并不是说这个
self?.removeFromFailed(type: type)
一定是错误的根源,但乍一看它是最有可能的候选者。如果这不是问题,请逐行注释掉,以找出闭包内的哪一行使编译器感到困惑。
就我个人而言,我也会消除那些不必要的
catch
:
private func asyncUpload() async throws {
guard let image = self.manager?.getUserModel()?.image else { return }
let body = SetAvatarRequest(username: UserManager.shared.username, image: image)
try await withCheckedThrowingContinuation { continuation in
RESTClient.shared.uploadImage(
fileName: "\(UserManager.shared.username)_avatar",
path: "files/avatar/\(UserManager.shared.userId)",
body: body
) { result in
print(result)
switch result {
case .success:
UserManager.shared.setImage(image)
continuation.resume()
// self?.removeFromFailed(type: type)
case let .failure(error):
print("DEBUG: \(error)")
continuation.resume(throwing: error)
}
}
}
}
一些不相关的观察结果:
as Void
是不必要的,我将其删除了。
Apple 建议一般使用
withCheckedThrowingContinuation
而不是 withUnsafeThrowingContinuation
。
resume(returning: ())
可以简化为resume()
。
localizedDescription
中的error
用于UI呈现,但通常不足以用于调试目的。只需打印 error
。
我已将其更改为
throws
的方法。作为一般规则,抛出发生的任何错误。好吧,如果调用者想要忽略发生的任何错误,那么好吧,it 可以选择用 try?
而不是 try
来忽略错误。但这应该是在调用点做出的决定,而不是融入到这个asyncUpload
方法中,恕我直言。
但是,一般来说,捕获错误而不重新
throw
(就像第一个示例一样)是错误的。或者,更简单地说,消除整个 do
-try
-catch
。