swift 组合 `.collect` 方法在哪个线程上发出?

esi*_*ver 8 swift combine

.collectSwift 的组合中的操作将在哪个线程上发出预期的线程?

具体来说,我在第二个前提条件中看到此代码崩溃,但在第一个前提条件中没有崩溃:

return Publishers.MergeMany(publishers)
    .handleEvents(receiveOutput: { _ in
        precondition(Thread.isMainThread) // <- This is fine
    })
    .collect()
    .handleEvents(receiveOutput: { _ in
        precondition(Thread.isMainThread) // <- Crash is here
    })
Run Code Online (Sandbox Code Playgroud)

就好像该.collect操作正在选择一个不同的线程来使用,即使最终的发布者必须MergeMany在主线程上发出。我通过从 Firebase 上传的崩溃日志推断出此行为。谁能解释这种观察到的行为?

Sco*_*son 1

为了进行检查,请尝试使用dispatchPrecondition(condition: .onQueue(.main)). 这在 Swift 中相当于调用dispatch_assert_queue. 如果您阅读那里的文档,您将看到:

将dispatch_get_main_queue() 的结果传递给此函数可验证当前块是否已提交到主队列、或以它为目标的队列、或正在主线程上运行(在任何上下文中)。

请注意,它说“正在主线程上运行”

Grand Central Dispatch 可以在非主线程的线程上执行以主队列为目标的队列上的代码。因此,即使代码在至少目前是“主”执行上下文的上下文中运行,显式比较当前线程与主线程的前提条件检查也可能无效。

如果您查看标头文档,dispatch_get_current_queue您会发现:

当在主线程上调用dispatch_get_current_queue()时,它可能会或可能不会返回与dispatch_get_main_queue()相同的值。比较两者并不是测试代码是否在主线程上执行的有效方法(请参阅dispatch_assert_queue()和dispatch_assert_queue_not())。

在您的情况下,我怀疑收集事件正在针对主队列的队列上运行,并且代码不在主线程上运行,但操作系统确保您的代码不与主线程并行运行,因此没有竞争条件的机会。