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

时间:2020-04-14 20:41:33

标签: swift swiftui combine

我想与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($0)
    })

因此,我将 .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($0)
    }))

谢谢。

1 个答案:

答案 0 :(得分:5)

.sink运算符执行三件事:

  • 它使用您传递的两个闭包创建一个Subscribers.Sink
  • 它在上游subscribe上调用Publisher,并传递它创建的Sink
  • 它将创建一个AnyCancellable,该销毁后将取消Sink。它返回对此AnyCancellable的引用。

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

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

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

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