.send() 和 .sink() 似乎不再适用于 Xcode 11 Beta 5 中的 PassthroughSubject

Posted

技术标签:

【中文标题】.send() 和 .sink() 似乎不再适用于 Xcode 11 Beta 5 中的 PassthroughSubject【英文标题】:.send() and .sink() do not seem to work anymore for PassthroughSubject in Xcode 11 Beta 5 【发布时间】:2019-12-07 19:09:03 【问题描述】:

在下面的代码中,当按下按钮时,应该在控制台中打印“Test”,但事实并非如此。该事件不通过发布者发送。 知道 Xcode 11 Beta 5 中的 PassthroughSubject 发生了什么吗? (在 Xcode 11 Beta 4 中运行良好)

var body: some View   

    let publisher = PassthroughSubject<String, Never>()

    publisher.sink  (str) in  
        print(str)  
      
    return Button("OK")   
        publisher.send("Test")  
      

附:我知道按下按钮时还有其他方法可以打印字符串,我只想展示一个简单的发送接收示例

【问题讨论】:

【参考方案1】:

.sink() 返回一个AnyCancellable 对象。你永远不应该忽视它。 永远不要这样做

// never do this!
publisher.sink  ... 
// never do this!
let _ = publisher.sink  ... 

如果将其分配给变量,请确保它不是短命的。一旦可取消对象被释放,订阅也会被取消。

// if cancellable is deallocated, the subscription will get cancelled
let cancellable = publisher.sink  ... 

既然您要求在视图中使用sink,我将发布一种方法。但是,在视图中,您可能应该改用.onReceive()。它更简单。

使用接收器:

在视图中使用它时,您需要使用@State 变量,以确保它在生成视图主体后仍然存在。

DispatchQueue.main.async 是必需的,以避免在视图更新时修改状态。否则会出现运行时错误。

struct ContentView: View 
    @State var cancellable: AnyCancellable? = nil

    var body: some View 
        let publisher = PassthroughSubject<String, Never>()

        DispatchQueue.main.async 
            self.cancellable = publisher.sink  (str) in
                print(str)
            
        

        return Button("OK") 
            publisher.send("Test")
        
    

使用.onReceive()

struct ContentView: View 

    var body: some View 
        let publisher = PassthroughSubject<String, Never>()

        return Button("OK") 
            publisher.send("Test")
        
        .onReceive(publisher)  str in
            print(str)
        
    

【讨论】:

为了解除订阅,我使用了这样的东西:self.cancellable = publisher.sink(receiveCompletion: (completion) in self.cancellable = nil , receiveValue: (str) in print(str) )。这是正确的解决方案还是有更好的解决方案? 我不是Combine方面的专家,但它似乎是正确的;-) 作为一个 Combine 和响应式初学者,对于非常简单的任务,周围的许多示例似乎过于复杂:struct ContentView: View @State var string: String = "" didSet print(string) var body: some View return Button("OK") self.string = "Test" 抱歉内联代码。为什么我们要使用主题?我猜是因为它开辟了使用运算符等的机会?【参考方案2】:

订阅接收器时缺少 .store。 您可以使用 .onReceive,但您的代码没有接收到值,因为您需要添加 .store(in: &subscription)

var body: some View   
    var subscription = Set<AnyCancellable>()
    let publisher = PassthroughSubject<String, Never>()

    publisher.sink  (str) in  
        print(str)  
    .store(in: &subscription)

    return Button("OK")   
        publisher.send("Test")  
      

【讨论】:

以上是关于.send() 和 .sink() 似乎不再适用于 Xcode 11 Beta 5 中的 PassthroughSubject的主要内容,如果未能解决你的问题,请参考以下文章

带有视图的 UIView 过渡和设置框架不再适用于 iOS 8

UITableView scrollToRow 在添加新行后不再适用于 iOS 11

在 Eclipse Corrosion 上调试 rust 不再适用于全新安装

ERROR send 和 transfer 仅适用于 address 类型的对象,而不适用于 address

send() 调用仅适用于套接字中的 telnet

PowerManagement.Inhibit 适用于 dbus-python 但不适用于 dbus-send