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

标签 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)
    }))

提前致谢。

最佳答案

.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 ,这打破了保持它活着的保留周期,因此 SinkSubscription 也被销毁,不会留下内存泄漏。

    关于swift - .sink 和 Subscribers.Sink 有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61216852/

    相关文章:

    swift - Alamofire 中的 CURL 命令与 swift

    swift - TextField 值可以在 TextFieldStyle 中使用吗?

    network-programming - 当发布者失败时,合并接收器无法完成

    swift - 为什么 `Publishers.Map`会急切的消费上游值呢?

    swift - 使用 Core Data 通过 UIProgressView 在 Swift 中异步插入数据

    ios - 将标签放在 ScrollView 中每个元素的上方?

    ios - 迁移到 Twilio Voice 5.0(iOS 13、Xcode 11): Custom incoming call view controller, 拒绝来电问题

    swiftui - 如何在 iOS 15 中使用 SwiftUI 在特定 View 中隐藏 TabBar

    swift - iOS 14 WidgetKit 中的动画

    binding - SwiftUI 在多个类之间传递数据