【问题标题】:Converting one publisher into another publisher in Combine在 Combine 中将一个发布者转换为另一个发布者
【发布时间】:2021-04-23 03:09:52
【问题描述】:

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

我的网络电话是

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

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

【问题讨论】:

  • 您没有提供足够的信息。当我通过弥补缺失的东西来提供足够的信息时,你的代码编译得很好!请展示足够多的真实代码,让我尝试编译它并得到你得到的错误。
  • @matt 请看我的新编辑。
  • Combine 有解码操作符时为什么需要解码函数?
  • @JoakimDanielson 因为目的是构建一个通用 NetworkRequest,它可以与其他形式的数据一起使用,例如构建 UIImage 而不仅仅是解码 JSON

标签: ios swift combine


【解决方案1】:

您只是在这里类型不匹配。 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 不匹配。

【讨论】:

  • 是的,我在添加 .eraseToAnyPublisher() 时已经这样做了,我得到“表达式类型不明确,没有更多上下文”
  • 查看我对问题的编辑
  • 为什么实际上不匹配? load 和 decode 都是 NetworkRequest 协议的一部分,因此当一个类实现 NetworkRequest 时,这两种方法的泛型类型 model 不应该相同吗?
  • @dev_ios999 因为 - 至少在有问题的代码中 - load 在其函数签名中定义了自己的附加(尽管具有相同的名称)泛型类型。所以,删除它。
  • @dev_ios999,我没有解决这个问题吗?我在更新的答案中展示了如何定义load。从函数签名中删除model,就像decode 一样,它将使用关联类型model(并且请大写您的类型 - 这是采用的约定)
猜你喜欢
  • 2021-08-21
  • 2019-11-30
  • 2021-05-25
  • 1970-01-01
  • 1970-01-01
  • 2020-08-05
  • 1970-01-01
  • 1970-01-01
  • 2019-11-08
相关资源
最近更新 更多