让自定义 Publisher 在 Swift Combine 上的不同 DispatchQueue 上运行

Posted

技术标签:

【中文标题】让自定义 Publisher 在 Swift Combine 上的不同 DispatchQueue 上运行【英文标题】:Make custom Publisher run on a different DispatchQueue on Swift Combine 【发布时间】:2020-03-07 22:20:58 【问题描述】:

我使用以下代码在 Swift Combine 中创建了一个返回自定义发布者的函数:

func customPubliher() -> AnyPublisher<Bool, Never> 
    return Future<Bool, Never>  promise in
        promise(.success(true))
    .eraseToAnyPublisher()

然后我使用以下代码订阅了这个发布者:

customPublisher()
    .subscribe(on: DispatchQueue.global())
    .map  _ in
        print(Thread.isMainThread)
    
    .sink(receiveCompletion:  _ in , receiveValue:  value in
        // Do something with the value received
    ).store(in: &disposables)

但即使我在订阅时添加了.subscribe(on: DispatchQueue.global()) 行,代码不会在不同的队列中执行(.map 中的print 输出为真)。

但是,如果我将自定义发布者替换为内置的组合发布者之一,例如 Just()(见下文),则相同的代码将在不同的队列上正常执行:

Just(true)
    .subscribe(on: DispatchQueue.global())
    .map  _ in
        print(Thread.isMainThread)
    
    .sink(receiveCompletion:  _ in , receiveValue:  value in
        // Do something with the value received
    ).store(in: &disposables)

上面代码中的.map 输出错误。

我在使用自定义发布者时做错了什么?我希望它在不同的队列上运行,就像 Just() 发布者一样。

【问题讨论】:

您的代码在 Playground 中按预期工作 【参考方案1】:

在我对您的代码的测试中,我得到了false。实际上DispatchQueue 与某个特定线程没有一对一的关系,它是一个执行队列并指定DispatchQueue.global() 你要求系统选择一些空闲队列 来执行你的任务默认优先级。因此,由系统决定在哪个队列和哪个线程中执行您的任务。

如果你故意想强制它进入后台,那么使用

.subscribe(on: DispatchQueue.global(qos: .background))

【讨论】:

谢谢,就是这样。但是,我发现有趣的是,当我使用 DispatchQueue.global() 时,我的自定义发布者中的代码似乎总是在主线程上执行,但是当我使用 Just() 时,它似乎总是在后台线程中执行。无论如何,我现在使用的是正确的队列。

以上是关于让自定义 Publisher 在 Swift Combine 上的不同 DispatchQueue 上运行的主要内容,如果未能解决你的问题,请参考以下文章

无法让自定义 RKBlockValueTransformer 与 RestKit 一起正常工作

无法让自定义的活动指示器生成动画

如何在视图中“解包”Publisher 对象 [swift]

Swift 中的自定义输入视图

使用 Swift Combine 创建一个 Timer Publisher

Swift Publisher 5.5.3安装教程