提问人:RadiantReasons 提问时间:11/10/2023 更新时间:11/10/2023 访问量:57
无法在没有类型批注的情况下推断闭包类型。Swift 5、XCode 15.0、RxSwift
Unable to infer closure type without a type annotation. Swift 5, XCode 15.0, RxSwift
问:
我的第一篇文章,所以我为缺乏冗长或知识而道歉。我对 Swift 很陌生。 我正在使用 RxSwift 来帮助同时运行对后端的 HTTP 调用,然后我将其压缩到单个可观察对象中,然后数据绑定到视图。
对于该过程的一部分,我正在从 RxSwift 创建一个 Single,然后根据视图将其压缩或与其他 HTTP 响应合并。
最初,我得到了一个“没有类型注释就无法表达类型”的闭包,并在 Single.create() 的函数调用中定义了闭包,所以我打破了闭包。这是整个函数的样子:
static func SendSingleRequest<ModelType>(_ request: any APIRequest, _ ModelType: some Decodable) -> Single<ModelType> {
let clo : (Single) -> Disposable = { single in
do{
self.session.dataTask(with: request.url) { (data, response, error) in
do {
let model = try JSONDecoder().decode(ModelType.self, from: data ?? Data())
single(.success(model))
} catch let jsonError as NSError {
print("Json decode failed: \(jsonError.localizedDescription)")
single(.failure(jsonError))
}
}
return Disposables.create()
}
};
return Single<ModelType>.create(subscribe: clo)
}
从本质上讲,我正在尝试将闭包放在 .create 函数中。我意识到 .create() 的函数定义包括 @escaping 关键字,但这似乎不是问题。如果我错了,请纠正我。
最后,在闭包定义行(第 2 行)中弹出一个错误,指出“Unable to 推断闭包类型没有类型注释。同样,我对 swift 非常陌生。
尽管显式定义了类型,但如何避免此错误?
老实说,我尝试了函数定义的不同排列,反复试验。没抱太大期望。
我试过在不同的地方定义闭包,这在理论上不会改变代码,但我希望。
我尝试重新排列传递到此函数的内容的整体结构,因此我不必处理某些变量,但这与我所能做到的一样简单。
总的来说,在阅读了有关该问题的信息后,我一直在做很多猜测和检查,我要么遇到另一个类型错误,要么遇到正常错误。
答:
您没有定义 .它必须是可解码的。这将编译:ModelType
static func SendSingleRequest<ModelType>(_ request: any APIRequest, _ type: ModelType.Type) -> Single<ModelType>
where ModelType: Decodable {
Single.create { completion in
self.session.dataTask(with: request.url) { data, response, error in
do {
let model = try JSONDecoder().decode(ModelType.self, from: data ?? Data())
completion(.success(model))
} catch {
completion(.failure(error))
}
}
return Disposables.create()
}
}
然而,对于你正在尝试做的事情来说,它是否严重不足(在 Swift 中,函数名称总是以小写字母开头。
- 一次性用品应该取消任务。
- 您根本没有检查响应对象。
- 仅接受 a 而不是 whole 会限制您执行标准 REST 调用的能力。
URL
URLRequest
最好的办法是使用 RxCocoa 的功能。它为您处理所有繁重的工作。因此,更好的翻译应该是这样的:data
static func sendSingleRequest<ModelType>(_ request: any APIRequest, _ type: ModelType.Type) -> Single<ModelType>
where ModelType: Decodable {
session.rx.data(request: URLRequest(url: request.url))
.decode(type: ModelType.self, decoder: JSONDecoder())
.asSingle()
}
更好的方法是使用 URLRequest,而不仅仅是 URL。另外,当您需要原始数据而不是使用 JSON 时呢?(例如,下载图像时。
像这样的东西会好得多:
// defines an APIRequest by the URLRequest needed to make the request and the
// function needed to parse the response
struct APIRequest<Element> {
let urlRequest: URLRequest
let handleResponse: (Data) throws -> Element
}
// when you don't need the response, use this init to create the request
extension APIRequest where Element == Void {
init(urlRequest: URLRequest) {
self.urlRequest = urlRequest
self.handleResponse = { _ in }
}
}
// this init is for when the response is decodable via a JSONDecoder.
// we pass in the Decoder so that we can configure it.
extension APIRequest where Element: Decodable {
init(urlRequest: URLRequest, decoder: JSONDecoder) {
self.urlRequest = urlRequest
self.handleResponse = { try decoder.decode(Element.self, from: $0) }
}
}
// the actual send is laughably simple when you use the tools available in Rx
extension URLSession {
func sendSingleRequest<Element>(_ request: APIRequest<Element>) -> Single<Element> {
self.rx.data(request: request.urlRequest)
.map(request.handleResponse)
.asSingle()
}
}
我在我的 CLE 库中使用了与上面非常相似的东西。
评论