.sink 和 Subscribers.Sink 有什么区别?

What's the difference between .sink and Subscribers.Sink?

我想用 Future 做一个异步作业。 但是下面的 .sink() 闭包 永远不会被调用。 貌似Future的实例一调用就释放了

    Future<Int, Never> { promise in
        DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
            promise(.success(1))
        }
    }
    .receive(on: DispatchQueue.main)
    .sink(receiveCompletion: { completion in
        print(completion)
    }, receiveValue: {
        print([=11=])
    })

所以我将 .sink() 闭包 替换为 .subscribe(Subscribers.Sink()) 如下所示。它工作正常。 但问题是我不明白为什么它工作正常。 :( 在我看来是一样的。 这两个代码有什么区别?我什么时候可以使用 .sink(),什么时候不能使用?

    Future<Int, Never> { promise in
        DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
            promise(.success(1))
        }
    }
    .receive(on: DispatchQueue.main)
    .subscribe(Subscribers.Sink(receiveCompletion: { completion in
        print(completion)
    }, receiveValue: {
        print([=12=])
    }))

提前致谢。

.sink 运算符做三件事:

  • 它使用您传递给它的两个闭包创建一个 Subscribers.Sink
  • 它在上游 Publisher 上调用 subscribe,传递它创建的 Sink
  • 它创建了一个 AnyCancellable,当它被销毁时,取消了 Sink。它 returns 对此 AnyCancellable 的引用。

AnyCancellable 是引用计数对象。当对 AnyCancellable 的最后一个引用被销毁时,AnyCancellable 本身也被销毁。那时,它调用自己的 cancel 方法。

在您的第一个示例中,您没有保存 .sink 返回的 AnyCancellable。所以 Swift 立即销毁它,这意味着它立即取消订阅。一秒钟后,您的 asyncAfter 闭包调用 promise,但订阅已被取消,因此您的 receiveValue 闭包未被调用。

在您的第二个示例中,由于您正在创建 Subscribers.Sink 对象并将其传递给自己 subscribe,因此不会创建 AnyCancellable 来包装 Sink。所以没有什么会自动破坏订阅。一秒钟后,asyncAfter 闭包调用 promise。由于订阅没有被销毁,它仍然存在,所以你的 receiveValue 闭包被调用,然后你的 receiveCompletion 闭包被调用。

所以这实际上是一个非常有趣的使用 Subscribers.Sink 而不是 .sink 运算符。使用 .sink,您 必须 保存返回的 AnyCancellable,否则订阅将立即取消。但是通过直接使用 Subscribers.Sink,您可以创建一个持续到完成的订阅,并且您无需保存任何内容。当订阅完成时(使用 .finished.failure),Sink 丢弃 Subscription,这打破了保持它存活的保留周期,因此 SinkSubscription 也被销毁,没有内存泄漏。