在 Combine 中将一个发布者转换为另一个发布者
Converting one publisher into another publisher in 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
我不太确定我做错了什么。我只是想使用解码方法来获取发布者。
您只是这里的类型不匹配。 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
returns Self.Model
,但是 load
想要 return 它自己的 Model
,所以不匹配。
解决方案是简单地从签名中删除函数的 Model
:
func load(_ url: URL, ...) -> AnyPublisher<Model, Error>
Combine 大量使用类型推断,这在它工作时大大简化了事情,或者在它不工作时给出了神秘和错位的错误。要使用 Combine 诊断此类错误,请使用显式类型。例如,在 flatMap
中明确指定您要 return 的类型:
.flatMap(maxPublishers: .max(1)) { pair -> AnyPublisher<Model, Error> in
self.decode(pair.data)
}
以上会抱怨 Self.Model
和 Model
不匹配。
我是组合新手,正在尝试为我的应用程序编写网络层。
我的网络电话是
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
我不太确定我做错了什么。我只是想使用解码方法来获取发布者。
您只是这里的类型不匹配。 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
returns Self.Model
,但是 load
想要 return 它自己的 Model
,所以不匹配。
解决方案是简单地从签名中删除函数的 Model
:
func load(_ url: URL, ...) -> AnyPublisher<Model, Error>
Combine 大量使用类型推断,这在它工作时大大简化了事情,或者在它不工作时给出了神秘和错位的错误。要使用 Combine 诊断此类错误,请使用显式类型。例如,在 flatMap
中明确指定您要 return 的类型:
.flatMap(maxPublishers: .max(1)) { pair -> AnyPublisher<Model, Error> in
self.decode(pair.data)
}
以上会抱怨 Self.Model
和 Model
不匹配。