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

Unable to infer closure type without a type annotation. Swift 5, XCode 15.0, RxSwift

提问人:RadiantReasons 提问时间:11/10/2023 更新时间:11/10/2023 访问量:57

问:

我的第一篇文章,所以我为缺乏冗长或知识而道歉。我对 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 非常陌生。

尽管显式定义了类型,但如何避免此错误?

老实说,我尝试了函数定义的不同排列,反复试验。没抱太大期望。

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

我尝试重新排列传递到此函数的内容的整体结构,因此我不必处理某些变量,但这与我所能做到的一样简单。

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

swift xcode 泛型 闭包 rx-swift

评论


答:

0赞 Daniel T. 11/10/2023 #1

您没有定义 .它必须是可解码的。这将编译: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 调用的能力。URLURLRequest

最好的办法是使用 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 库中使用了与上面非常相似的东西。