简体   繁体   中英

SwiftUI / Combine Pass data between two models

I have question regarding how to pass data between two models.

struct SettingsCell: View {
    @State var isOn: Bool

    var body: some View {
        Toggle(name, isOn: $isOn)
    }
}

class SettingsModel: ObservableObject {
    @Published var someValue: Bool = false
}

struct SettingsView: View {
    @ObservedObject var model = SettingsModel()

    var body: some View {
        List {
            SettingsCell(isOn: model.someValue)
        }
    }
}

So i want to pass isOn state from cell, to main model, and react there. Send requests for example.

You need to declare isOn as @Binding in SettingsCell .

@State should only be used for properties initialised inside the View itself and must always be private . If you want to pass in a value that should update the View whenever it changes, but the value is created outside the View , you need to use Binding .

Another really important thing to note is that @ObservedObject s must always be injected into View s, you must not initialise them inside the view itself. This is because whenever an @ObservedObject is updated, it updates the view itself, so if you initialised the object inside the view, whenever the object updates the view, the view would create a new @ObservedObject and hence your changes wouldn't be persisted from the view to the model.

If you are targeting iOS 14 and want to create the model inside the view, you can use @StateObject instead.

struct SettingsCell: View {
    @Binding private var isOn: Bool

    init(isOn: Binding<Bool>) {
        self._isOn = isOn
    }

    var body: some View {
        Toggle(name, isOn: $isOn)
    }
}

class SettingsModel: ObservableObject {
    @Published var someValue: Bool = false
}

struct SettingsView: View {
    @ObservedObject private var model: SettingsModel

    init(model: SettingsModel) {
        self.model = model
    }

    var body: some View {
        List {
            SettingsCell(isOn: $model.someValue)
        }
    }
}

Binding is used in cases where the data is "owned" by a parent view - ie the parent holds the source of truth - and needs the child view to update it:

struct SettingsCell: View {
    @Binding var isOn: Bool // change to Binding

    var body: some View {
        Toggle(name, isOn: $isOn)
    }
}

struct SettingsView: View {
    // unrelated, but better to use StateObject
    @StateObject var model = SettingsModel() 

    var body: some View {
        List {
            // pass the binding by prefixing with $
            SettingsCell(isOn: $model.someValue)
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM