Swift 如何在请求同一链中的dataTaskPublisher时使用来自一个发布者的值?

Swift 如何在请求同一链中的dataTaskPublisher时使用来自一个发布者的值?,swift,combine,Swift,Combine,我是一个新的组合,并试图找出如何连锁出版商。我有一个发布服务器,它返回一个字符串值,我想用这个字符串值来构建一个URLRequest,而URLRequest又被传递给DataTaskPublisher。如果您有任何关于正确语法的帮助,我们将不胜感激 示例代码: struct ResultObject: Decodable {} func getValueKey() -> AnyPublisher<String, Error> { return Just("T

我是一个新的组合,并试图找出如何连锁出版商。我有一个发布服务器,它返回一个字符串值,我想用这个字符串值来构建一个URLRequest,而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 */
}
struct ResultObject:Decodable{}
func getValueKey()->AnyPublisher{
仅返回(“测试”)
.setFailureType(收件人:Error.self)
.删除任何发布者()
}
func performSearch(searchTerm:String)->AnyPublisher{
返回getValueKey().flatMap{valueKey in
let request:URLRequest=URLRequest(url:url(字符串):http://www.test.com/\(valueKey)“)!)
返回URLSession.shared.dataTaskPublisher(用于:请求)
.map{$0.data}
.decode(类型:[ResultObject].self,解码器:JSONDecoder())
}
.橡皮擦AnyPublisher()/*错误:表达式类型不明确,没有更多上下文*/
}
注意:我非常不确定最后一个
橡皮擦到任何出版商的位置

您有两个问题

首先,您给了
flatMap
的形式参数名称
valueKey
,但后来您尝试使用名称
引用它。这些需要匹配

其次,Swift无法推断多语句函数的返回类型,比如传递给
flatMap
的闭包。(它可以将参数类型推断为
getValueKey
返回的发布服务器的
Output
类型)

解决此问题的一般方法有两种:

  • 更改代码,使闭包只包含一条语句,
  • 显式地给出返回类型
将其重写为单个语句的一种方法是使用
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()
}
我提到的另一种方法是使闭包的返回类型显式。这很棘手,因为返回类型很复杂。您需要向右滚动才能看到整个内容:

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()
}
你有两个问题

首先,您给了
flatMap
的形式参数名称
valueKey
,但后来您尝试使用名称
引用它。这些需要匹配

其次,Swift无法推断多语句函数的返回类型,比如传递给
flatMap
的闭包。(它可以将参数类型推断为
getValueKey
返回的发布服务器的
Output
类型)

解决此问题的一般方法有两种:

  • 更改代码,使闭包只包含一条语句,
  • 显式地给出返回类型
将其重写为单个语句的一种方法是使用
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()
}
我提到的另一种方法是使闭包的返回类型显式。这很棘手,因为返回类型很复杂。您需要向右滚动才能看到整个内容:

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()
}

非常感谢您给出如此完整的答案!非常感谢您给出如此完整的答案!