skip to Main Content

I have a SwiftUI project using MVVM structure but I have lots of variables in View now, is that right?How can I improve this?

For example, this is my add record view

    @State private var money: String = ""
    @State private var desc: String = ""
    @FocusState var isDescFieldFocused: Bool
    @State private var showDatePicker: Bool = false
    @State private var showingAlert: Bool = false
    @State private var showConstantlyAlert: Bool = false
    @State private var showKeyPad: Bool = false
    @State private var showCatesPanel: Bool = false
    @State private var selectedCate: String = ""

Should I put all these in View Models?

2

Answers


  1. Like you said, you could create a view model for that view, which would either be a @StateObject or @ObservedObject (depends on whether you want to create the view model within the view or inject it from outside).

    I tend to create view models for my views if they require any logic and not only display information which is passed down from parent views.

    Thus, you could do this:

    final class YourNameViewModel: ObservableObject {
    
        @Published var money = ""
        // other properties
    
        init() {
            ...
        }
    
    }
    

    and use it within your view like so:

    struct YourNameView: View {
    
         @StateObject var vm = YourNameViewModel()
         // or @ObservedObject var vm: YourNameViewModel (if you want to pass it down from a parent view)    
    
    }
    
    Login or Signup to reply.
  2. Apple addresses this in Data Essentials in SwiftUI WWDC 2020 at 4:18

    EditorConfig can maintain invariants on its properties and be tested
    independently. And because EditorConfig is a value type, any change to
    a property of EditorConfig, like its progress, is visible as a change
    to EditorConfig itself. 4:18

    So in your case it would look like:

    struct MyConfig {
        var money: String = ""
        var desc: String = ""
        var showDatePicker: Bool = false
        var showingAlert: Bool = false
        var showConstantlyAlert: Bool = false
        var showKeyPad: Bool = false
        var showCatesPanel: Bool = false
        var selectedCate: String = ""
    
        mutating func otherLogic() {}
    }
    
    struct MyView {
    
        @State var config = MyConfig()
        @FocusState var isDescFieldFocused: Bool
    

    Just to let you know, MVVM (i.e. using objects for view data) is not suitable for SwiftUI because the View struct and property wrappers is equivalent to a view model object but faster and less error-prone. If you use actual objects instead of learning SwiftUI’s features you’ll have problems.

    The time we use an ObservableObject in SwiftUI is for model data, i.e. the environment object/singleton that stores the arrays of model structs in @Published properties and is responsible for loading/saving/syncing etc. the model data etc. That is covered in the same video later on, from about 9mins 30secs.

    For write-access to model data we use @Binding.

    We used to also use @StateObject when we need a reference type as state, e.g. for async features with lifetime tied to something on screen like networking, but that is pretty much redundant now we have the .task(id:) modifier which achieves the same thing. Because we can simply set the result (or thrown error) of await to an @State and the task will be automatically cancelled when the view disappears (and also cancelled and restarted if an id passed to task(id:) changes). It would take a lot of code and testing to reimplement that behaviour in a @StateObject.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search