SwiftUI : Binding UI controls directly to model's properties vs declaring separate @State for each input

248 Views Asked by At

I am looking for some suggestion on what is the recommended practice on SwiftUI

When we design a view where we need to capture inputs from user, those inputs then need to be captured into a model object which will finally be saved and retrieved later to display in some scene, what is recommended

Option #1. Each subview to have its local @State variables which are bind-ed to control like TextField, Pickers, Toggle etc and then we should write some code to transfer these to model object

model for Option#1

struct PersonModel: Codable, Identifiable {
    var id: UUID
    var name: String
    var dateOfBirth: Date?
    var height: Double?
    var weight: Double?
}

Option #2. Should we bind the model's properties directly to TextField, Pickers, Toggle etc.

model for Option#2

struct PersonModel: Codable, Identifiable {
var id: UUID
var name: String
var dateOfBirth: Date?
var height: Double?
var weight: Double?

var heightInput: String {
    didSet {
        self.height = heightInput.DoubleOrNil()
    }
}

var weightInput: String {
    didSet {
        self.weight = weightInput.DoubleOrNil()
    }
}

}

In Option#1 I see a need to write a lot of code just to capture the state and then transfer state to model but in Option #2 the state is already captured in the model object so less code. Plus any interrelationship cum dependencies that trigger a change in other properties can be coded in the model itself (in didSet). For example, I can bind heightInput and weight input to TextField and extract out the underlying value within Model itself instead of processing String in View and transferring it into Double type property somewhere in View

Option #3. Like we break a single view into subviews, should we also break Model (struct) into smaller sub-models and assign sub-model to sub-views? Like below

struct BodyStatictics {
    var heightInput: String {
        didSet {
            self.height = heightInput.DoubleOrNil()
        }
    }
    
    var weightInput: String {
        didSet {
            self.weight = weightInput.DoubleOrNil()
        }
    }
    
    var height: Double?
    var weight: Double?
}

struct BirthData {
    var dateOfBirth: Date?
    var location: String
}

struct PersonModel: Codable, Identifiable {
    var id: UUID
    var name: String
    var birthData: BirthData
    var bodyStats: BodyStatictics
}

struct MainView: View {
    @State private var modelInstance: PersonModel
    init(instance: PersonModel) {
        _modelInstance = State(initialValue: instance)
    }
    var body: some View {
        NameView(name: self.$modelInstance.name)
        BirthDataView(instance: self.$modelInstance.birhData)
        BodyStatisticsView(name: self.$modelInstance.bodyStats)
    }
}

Are there any pitfalls one should be aware of before adopting one of the above practices (or design choice) so that any later on refactoring or mismanagement can be avoided now?

I find the binding the model's properties directly to UI controls easier rather than creating local @State in each view as it leads to less code in UI and centralized code in Model. Is that right assessment or wrong assessment?

0

There are 0 best solutions below