我的第一篇文章,因此我为缺乏冗长或知识而道歉。我对斯威夫特很陌生。 我使用 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 行),并且在所有情况下,我都会返回一个 Disposable。再说一遍,我对 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 中,函数名称总是以小写字母开头。)
URL
而不是整个 URLRequest
会限制您执行标准 REST 调用的能力。最好的选择是使用 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()
}
}