1

For a something that would be simple with UIKit, I'm struggling to find the best solution using SwiftUI. I would appreciate any help / guidance.

I have an array of objects, each of which can be selected. My first attempt do display this was:

final class MeasurementSelections: ObservableObject {

    struct Measurement: Identifiable {
        let id = UUID()
        let name: String
        var isSelected: Bool = false

        init(name: String) {
            self.name = name
        }
    }

    @Published var measurements: [Measurement]

    init(measurements: [Measurement]) {
        self.measurements = measurements
    }
}

struct Readings: View {

    @ObservedObject var model: MeasurementSelections

    var body: some View {
        List(0..<model.measurements.count) { index in
            Text(self.model.measurements[index].name)
                .font(.subheadline)
            Spacer()
            Toggle(self.model.measurements[index].name, isOn: self.$model.measurements[index].isSelected)
                .labelsHidden()
        }
    }
}

This is fairly straightforward, but the use of a Range and the replication of self.model.measurements[index] doesn't seem right… I'd rather have a separate View that takes a Measurement as a parameter.

Follow this answer, my next attempt was…

final class MeasurementSelections: ObservableObject {

    struct Measurement: Identifiable {
        let id = UUID()
        let name: String
        var isSelected: Binding<Bool>

        private var selected: Bool = false

        init(name: String) {
            self.name = name

            let selected = CurrentValueSubject<Bool, Never>(false)
            self.isSelected = Binding<Bool>(get: { selected.value }, set: { selected.value = $0 })
        }
    }

    @Published var measurements: [Measurement]

    init(measurements: [Measurement]) {
        self.measurements = measurements
    }
}

struct Readings: View {

    @ObservedObject var model: MeasurementSelections

    var body: some View {
        VStack {
            MeasurementView(measurement: measurement)
        }
    }
}

struct MeasurementView: View {
    let measurement: MeasurementSelections.Measurement
    var body: some View {
        HStack {
            Text(measurement.name)
                .font(.subheadline)
            Spacer()
            Toggle(measurement.name, isOn: measurement.isSelected)
                .labelsHidden()
        }
    }
}

This is nicer as regards the view separation, but now the MeasurementSelections class has become significantly more complicated, and requires Combine.

Is there a solution to this problem that keeps the view separation but with a simpler model?

Additionally, I'd eventually like the MeasurementSelections to expose a bindable(?) Bool property that is set when ANY of its measurements are selected, which might inform your answer

1 Answer 1

-1

the use of a Range and the replication of self.model.measurements[index] doesn't seem right…

There is no replication, you manipulating data in your model directly, without any "replication"

import SwiftUI

struct Data: Identifiable {
    let id = UUID()
    var name: String
    var on_off: Bool
}

class Model: ObservableObject {
    @Published var data = [Data(name: "alfa", on_off: false), Data(name: "beta", on_off: false), Data(name: "gama", on_off: false)]
}



struct ContentView: View {
    @ObservedObject var model = Model()
    var body: some View {
        List(0 ..< model.data.count) { idx in
            HStack {
                Text(verbatim: self.model.data[idx].name)
                Toggle(isOn: self.$model.data[idx].on_off) {
                    EmptyView()
                }
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

**enter image description here**

Sign up to request clarification or add additional context in comments.

2 Comments

That’s no different from my first example.
Yes, there is no difference, use it! There is no replication, it is most straightforward way. And best, it is fully declarative (SwiftUI) way.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.