无法在没有类型注释的情况下推断闭包类型。 Swift 5、XCode 15.0、RxSwift

问题描述 投票:0回答:1

我的第一篇文章,因此我为缺乏冗长或知识而道歉。我对斯威夫特很陌生。 我使用 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 很陌生。

尽管明确定义了类型,如何避免此错误?

我已经尝试过不同的函数定义排列,诚实地反复试验。没想到太多。

我已经尝试在不同的地方定义闭包,这在理论上不会改变代码,但我希望如此。

我尝试重新安排传递给该函数的整体结构,这样我就不必处理某些变量,但这已经是我能做到的最简单的了。

总的来说,我在阅读问题后做了很多猜测和检查,我要么遇到了另一种类型的错误,要么遇到了正常错误。

swift xcode generics closures rx-swift
1个回答
0
投票

您没有定义您的

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()
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.