在Combine中的flatMap中发布者过早完成

我有这个最小的例子:

import UIKit
import Combine

var values = [1,2,3,4,5]

var cancel = values.publisher
    .delay(for: 0.1, scheduler: DispatchQueue.global())
    .print()
    .flatMap() { i in
        [i].publisher.first()
    }
    .sink { completion in
        print("Received Completion: (completion)")
    } receiveValue: { v in
        print("Received Value: (v)")
    }

我的期望是源发布者将 1 到 5 的值发送到流中。每个数字都被转换成(只是为了它)一个新的发布者,它发出第一个值然后完成。由于这是对每个数字完成的,我希望所有值都到达接收器。然而,情况并非如此。输出如下所示:

request unlimited
receive value: (1)
Received Value: 1
receive value: (2)
Received Value: 2
receive value: (4)
Received Value: 4
receive finished
Received Completion: finished
receive value: (3)
receive value: (5)

实际上,在完成事件到达之前,只有 3 个值到达接收器。为什么是这样?该文件指出:

新发布者的成功完成并没有完成整个流。

更奇怪的,当你更换.flatMap().flatMap(maxPublishers: .max(1)),并添加一个.share()原始的源出版商只有第一个值,使得它下沉。

任何指针都非常感谢!

回答

你的使用DispatchQueue.global()是问题。所述values.publisher发送所有其输出,和它的完成,向下游delay操作者尽快values.publisher接收订阅。的delay操作者的时间表六个块(5用于输出数字和一个用于完成)上运行DispatchQueue.global()以后0.1秒。

DispatchQueue.global()并发队列。这意味着它可以同时运行任意数量的块。因此无法保证六个预定区块中的哪一个将首先完成。

将并发队列用作组合调度程序通常是一个坏主意。您应该改用串行队列。这是一个简单的例子:

var cancel = values.publisher
    .delay(for: 0.1, scheduler: DispatchQueue(label: "my queue"))
    .print()
    .flatMap() { i in
        [i].publisher.first()
    }
    .sink { completion in
        print("Received Completion: (completion)")
    } receiveValue: { v in
        print("Received Value: (v)")
    }

但是您可能希望创建一次队列并将其存储在一个属性中,这样您就可以将它与多个发布者一起使用。

如果您确实希望将输出传送到主队列(可能是因为您要使用它们来更新视图),则应该使用DispatchQueue.main.


以上是在Combine中的flatMap中发布者过早完成的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>