swift - collect() 方法的不明显行为
问题描述
private lazy var dispatchQueue = DispatchQueue(
label: "\(type(of: self))",
attributes: .concurrent
)
func makeArrayGreatAgain(elem0: SomeStruct, elem1: SomeStruct, elem2: SomeStruct, elem3: SomeStruct) {
[elem0 elem1, elem2, elem3]
.publisher
.receive(on: dispatchQueue)
.tryMap { print("R", $0) } // Void
.eraseToAnyPublisher() // just copy-pasted
.collect(4)
.sink { result in print("E", result) }
receiveValue: { result in print("S", result) }
}
我不时看到不同的日志。
例如:
R
R
R
S [(), (), ()]
E
R
或者
R
R
R
R
S [(), (), (), ()]
E
为什么?我想获得整个结果:
R
R
R
R
S [(), (), (), ()]
E
我怎样才能做到这一点?
评论
collect()
没有参数也会出现同样的问题
解决方案
在您的示例中,这与在并发队列上接收的.collect()
所有内容无关。receive(on:)
因此,值和(对于这个问题至关重要)完成信号是同时处理的,因此它们发出的顺序与它们到达的顺序不同。
因此,有时,完成信号实际上会在所有值到达之前到达下一步。
如果下一步是collect
发布者,当它看到完成时,它会发出一个它在该点之前收到的值的数组,并且也会完成。
为确保您按顺序接收值,请使用串行队列:
var serialQ = DispatchQueue(
label: "foo"
)
let c = ["1", "2", "3", "4"]
.publisher
.receive(on: serialQ) // or receive(on: DispatchQueue.main)
.map { print("R", $0) }
.collect()
.sink (receiveCompletion: { print("E", $0) },
receiveValue: { print("S", $0) })
你将永远得到:
R 1
R 2
R 3
R 4
S [(),(),(),()]
E finished
推荐阅读
- c++ - 无法弄清楚如何使用 SDL2 正确格式化 Makefile。未定义参考
- java - 我的代码一直在打印“ [Ljava.lang.String;@4e50df2e”,不太确定该放在哪里以及如何放置 toString()
- java - 需要使用 java 的 lamda 表达式打印字符串的最后一位
- java - 调试:合并排序
- selenium - 使用 goroutine 意外关闭 selenium
- c - C 编程中的蛮力搜索,在 C 编程中读取 .fna 文件
- go - 将 int 切片转换为十六进制值的更好方法
- java - 使用 Spring clound contract 为云合约端点编写生产者测试
- c# - 如何在 C# 中使用 LINQ 应用右外连接?
- python - 在两条以上的曲线之间填充 matplotlib