对于Xcode 11 Beta 5中的PassthroughSubject,.send()和.sink()似乎不再起作用

Sor*_*ica 3 swiftui combine

在下面的代码中,当按下Button时,应该在控制台中打印“ 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")  
    }  
}
Run Code Online (Sandbox Code Playgroud)

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

kon*_*iki 9

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

// never do this!
publisher.sink { ... }
Run Code Online (Sandbox Code Playgroud)
// never do this!
let _ = publisher.sink { ... }
Run Code Online (Sandbox Code Playgroud)

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

// if cancellable is deallocated, the subscription will get cancelled
let cancellable = publisher.sink { ... }
Run Code Online (Sandbox Code Playgroud)

由于您要求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")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

使用 .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)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


zdr*_*kin 8

当您订阅接收器时,您缺少 .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")  
    }  
}
Run Code Online (Sandbox Code Playgroud)