首页 > 解决方案 > 在 Combine 中将一个发布者转换为另一个发布者

问题描述

我是新手,我正在尝试为我的应用程序编写网络层。

我的网络电话是

protocol NetworkRequest {
    associatedtype model
    func decode(_ data:Data) -> AnyPublisher<model,Error>
}

extension NetworkRequest {

 fileprivate func load<model>(_ url:URL, session:NetworkSession = URLSession.shared) -> AnyPublisher<model,Error> {
    
    return session.loadData(for: URLRequest(url: url))
        .mapError { error in
            .network(description: error.localizedDescription)
        }
        .flatMap(maxPublishers: .max(1)) { pair in
            self.decode(pair.data)
        }
        .eraseToAnyPublisher()
        
 }

}

我的解码方法是

func decode(_ data:Data) -> AnyPublisher<model,Error>

我的 session.loadData 是

func loadData(for URLRequest: URLRequest) -> AnyPublisher<(data: Data, response: URLResponse), URLError>

问题是我收到一个错误Type of expression is ambiguous without more context

我不确定我在这里做错了什么。我只是想使用解码方法来获取发布者。

标签: iosswiftcombine

解决方案


您在这里只是类型不匹配。publisher是类型AnyPublisher,而您分配给它的类型是FlatMap. 这在使用运算符时通常会发生,解决方案是使用运算符进行类型擦除.eraseToAnyPublisher()

var publisher : AnyPublisher<Model, Error> = 
    session.loadData(for: URLRequest(url: url))
           .flatMap { (data,response) -> AnyPublisher<Model,Error> in
               self.decode(data)
           }
           .eraseToAnyPublisher() // add this

顺便说一句,您应该对类型使用 CapitalCase,例如Model


更新:根据您的问题更改

这又是一个类型不匹配,但在这种情况下,有一个Model类型。当你load像这样声明你的函数时:

func load<Model>(_ url: URL, ...) -> AnyPublisher<Model,Error> {

Model函数的泛型类型与关联类型Model不同——它们是完全不同的类型,只是名称相同。所以,decode返回Self.Model,但load想返回自己的Model,所以不匹配。

解决方案只是Model从签名中删除函数:

func load(_ url: URL, ...) -> AnyPublisher<Model, Error>

Combine 大量使用类型推断,当它起作用时会大大简化事情,或者在不起作用时会给出神秘和错位的错误。要使用 Combine 诊断此类错误,请使用显式类型。例如,在里面flatMap明确指定你要返回的类型:

.flatMap(maxPublishers: .max(1)) { pair -> AnyPublisher<Model, Error> in
     self.decode(pair.data)
}

上面会抱怨Self.Model和的不匹配Model


推荐阅读