首页 > 解决方案 > Combine: Init mutating 'self' parameter

问题描述

I'm messing around with Combine code and Swift UI and came across this problem. Effectively I want to pass a Publisher into a View and have that View update every time the publisher publishes an update.

Here's a sample playground that will not compile. Instead it puts up an error - Escaping closure captures mutating 'self' parameter on the .sink(... line.

import Combine
import SwiftUI

struct MyView: View {

    let cancellable: AnyCancellable
    @State var current: Int = 0

    init<P>(publisher: P) where P: Publisher, P.Output == Int, P.Failure == Never {
        cancellable = publisher.sink { value in
            self.current = value
        }
    }

    var body: some View {
        Text("\(current)")
    }
}

let subject = PassthroughSubject<Int, Never>()
let x = MyView(publisher: subject)
subject.send(5)

Currently I've changed the code to use an ObservableObject view model with the value inside it and telling that object to send an update. But I'm interested how others have gotten around this problem as I'd like a none view model option too.

What have you guys done?

标签: iosswiftswiftuicombine

解决方案


您可以使用onReceive订阅PublisherSwiftUI 中View的 Combine 。这样,SwiftUI 运行时将为您管理订阅,即使您的视图可能会被重新创建多次。

struct MyView: View {
    @State var current: Int = 0

    var body: some View {
        Text("\(current)")
            .onReceive(somePublisher) { self.current = $0 }
    }
}

但是,ObservableObject直接使用 s 通常是一个更好的主意,因为它们直接集成到 SwiftUI 中。


推荐阅读