我是新来的要合并的人,并试图弄清楚如何链接发布者。我有一个发布者,它返回一个我想用来构建URLRequest的字符串值,然后将其传递给DataTaskPublisher。使用正确语法的任何帮助将不胜感激!
示例代码:
struct ResultObject: Decodable {}
func getValueKey() -> AnyPublisher<String, Error> {
return Just("Test")
.setFailureType(to: Error.self)
.eraseToAnyPublisher()
}
func performSearch(_ searchTerm: String) -> AnyPublisher<[ResultObject], Error> {
return getValueKey().flatMap { valueKey in
let request: URLRequest = URLRequest(url: URL(string: "http://www.test.com/\(valueKey)")!)
return URLSession.shared.dataTaskPublisher(for: request)
.map { $0.data }
.decode(type: [ResultObject].self, decoder: JSONDecoder())
}
.eraseToAnyPublisher() /* Error: Type of expression is ambiguous without more context */
}
注意:我不确定最后一个eraseToAnyPublisher
答案 0 :(得分:1)
您有两个问题。
首先,您为flatMap
的形式参数指定了名称valueKey
,但后来尝试使用名称value
来引用它。这些需要匹配。
第二,Swift无法推断出多语句函数的返回类型,例如您要传递给flatMap
的闭包。 (它可以推断参数类型为Output
返回的发布者的getValueKey
类型。)
有两种一般方法可以解决此问题:
将其重写为单个语句的一种方法是使用map
运算符将传入的String
转换为URLRequest
,如下所示:
func performSearch(_ searchTerm: String) -> AnyPublisher<[ResultObject], Error> {
return getValueKey()
.map { URLRequest(url: URL(string: "http://www.test.com/\($0)")!) }
.flatMap {
return URLSession.shared.dataTaskPublisher(for: $0)
.map { $0.data }
.decode(type: [ResultObject].self, decoder: JSONDecoder())
}
.eraseToAnyPublisher()
}
我们还可以通过使用mapError
将URLError
转换为Error
然后将其他运算符移到flatMap
之外来减少嵌套:
func performSearch(_ searchTerm: String) -> AnyPublisher<[ResultObject], Error> {
return getValueKey()
.map { URLRequest(url: URL(string: "http://www.test.com/\($0)")!) }
.flatMap { URLSession.shared.dataTaskPublisher(for: $0).mapError { $0 as Error } }
.map { $0.data }
.decode(type: [ResultObject].self, decoder: JSONDecoder())
.eraseToAnyPublisher()
}
我提到的另一种方法是使闭包的返回类型明确。这很棘手,因为返回类型很复杂。您需要向右滚动才能看到整个内容:
func performSearch0(_ searchTerm: String) -> AnyPublisher<[ResultObject], Error> {
return getValueKey().flatMap { value -> Publishers.Decode<Publishers.Map<URLSession.DataTaskPublisher, Data>, [ResultObject], JSONDecoder> in
let request: URLRequest = URLRequest(url: URL(string: "http://www.test.com/\(value)")!)
return URLSession.shared.dataTaskPublisher(for: request)
.map { $0.data }
.decode(type: [ResultObject].self, decoder: JSONDecoder())
}
.eraseToAnyPublisher()
}
因此,当我们选择此解决方案时,我们通常希望使用eraseToAnyPublisher
来简化类型:
func performSearch1(_ searchTerm: String) -> AnyPublisher<[ResultObject], Error> {
return getValueKey().flatMap { value -> AnyPublisher<[ResultObject], Error> in
let request: URLRequest = URLRequest(url: URL(string: "http://www.test.com/\(value)")!)
return URLSession.shared.dataTaskPublisher(for: request)
.map { $0.data }
.decode(type: [ResultObject].self, decoder: JSONDecoder())
.eraseToAnyPublisher()
}
.eraseToAnyPublisher() /* Error: Type of expression is ambiguous without more context */
}