我想知道是否有可能访问在组合操作符链中使用的值。
例如,如果你有一个字符串数组,并且你下载了一个包含每个字符串的资源,是否有可能访问字符串本身?
也许一个伪代码的例子会帮助你更好地理解:
let strings = ["a", "b", "c"]
strings.publisher
.compactMap{ str in
URL(string: "https://someresource/(str)")
}
.flatMap { url in
URLSession.shared.dataTaskPublisher(for: url)
}
.map { $0.data}
.map { data in
// here I would need the "str" string from above
}
非常感谢你的帮助
Thx,格雷戈尔
Jake写下并删除的答案是正确的。我不知道他为什么删掉了;也许他觉得他不能用示例代码来支持它。但答案是完全正确的。如果稍后在管道中需要初始的str
值,则由您在每个步骤中继续传递它。您通常通过在每个阶段传递值的元组来实现这一点,以便字符串在链中足够低的位置进行检索。这是一个非常的组合编程策略。
对于一个简单的例子,看一下本文中心部分的Combine代码: https://www.biteinteractive.com/swift-5-5-asynchronous-looping-with-async-await/
正如我在文章中所说的:
你会发现,与GCD相反,局部变量只是神奇地"掉入"到较低作用域的嵌套完成处理程序中,Combine管道中的每一步都必须显式地传递后续步骤可能需要的所有信息。这可能导致一些相当笨拙的值在管道中工作,通常以元组的形式,如我在这里所示。
但我不认为那是个问题。相反,在我看来,明确说明管道中传递的内容似乎是一种清晰的收获。
为了进一步说明,这里重写了你的伪代码;这是真实的代码,您可以运行它并尝试一下:
class ViewController: UIViewController {
var storage = Set<AnyCancellable>()
override func viewDidLoad() {
super.viewDidLoad()
let strings = ["a", "b", "c"]
let pipeline = strings.publisher
.map { str -> (String, URL) in
let url = URL(string: "https://www.apeth.com/pep/manny.jpg")!
return (str, url)
}
.flatMap { (str, url) -> AnyPublisher<(String, (data: Data, response: URLResponse)), URLError> in
let sess = URLSession.shared.dataTaskPublisher(for: url)
.eraseToAnyPublisher()
let just = Just(str).setFailureType(to: URLError.self)
.eraseToAnyPublisher()
let zip = just.zip(sess).eraseToAnyPublisher()
return zip
}
.map { (str, result) -> (String, Data) in
(str, result.data)
}
.sink { comp in print(comp) } receiveValue: { (str, data) in print (str, data) }
pipeline.store(in: &storage)
}
}
这不是表示管道的唯一方法,但它确实有效,并且它应该为您提供一个起点。