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

use*_*557 3 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)
    })
Run Code Online (Sandbox Code Playgroud)

所以我将.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)
    }))
Run Code Online (Sandbox Code Playgroud)

提前致谢。

rob*_*off 8

.sink运营商做了三两件事:

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

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

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

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

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

  • `Subscribers.Sink` 符合 `Cancellable`。如果你将`Sink`保存在自己的属性中,则可以直接调用它的`cancel`方法。 (2认同)