SwiftUI Model with struct/Binding or class/ObservableObject?

I have an app I wrote many years ago in Objective-C that I had converted it to Swift, and now I converted it to SwiftUI. When converting to SwiftUI I had all my model files as structs. I decided to convert to the new Swift Navigation API released in iOS16, since the old way is deprecated and I would be gaining some features that I have wanted for years. However, this causes multiple infinite loops that I have been trying to track down for months. I finally requested Apple Developer Technical support, which ended up being no help. I then narrowed this issue down to using a binding and I think it is a bug so I submitted a bug report FB12069067 to Apple.

The only solution I see, without Apple acknowledging this is a bug and fixing it, it to convert all my model files from structs to class as ObservableObjects, and instead of passing a binding I can use the observed object. I’d have to change a significant amount of code, but I see no other solution. I have found an article by Apple that seems to imply that I should use a class for my model files.

https://developer.apple.com/documentation/swiftui/managing-model-data-in-your-app

I’m curious what everyone else is doing. When using SwiftUI, is your model with struct/Binding or class/ObservableObject?

Replies

When using SwiftUI, developers tend to use a mix of structs and classes for their models depending on the use case. Both approaches have their advantages and disadvantages.

Structs and Bindings:

Structs are value types, which means they are passed by value (copied) when used in functions or assigned to variables. They are lightweight and efficient, especially for small models. Using Binding with structs allows you to create two-way bindings between the UI and the model, enabling updates in the UI to propagate back to the model.

Classes and ObservableObjects:

Classes are reference types, which means they are passed by reference (memory address) when used in functions or assigned to variables. They allow for more complex behaviors, including inheritance. Using ObservableObject and @Published with classes allows you to create data models that automatically notify their observers (e.g., SwiftUI views) when their properties change, which in turn triggers a UI update. As you've found, using ObservableObjects might be a better fit for your particular case due to the issue you encountered with the new Swift Navigation API. Converting your models to classes and making them conform to the ObservableObject protocol would allow you to use @ObservedObject or @StateObject for passing the models around, which can help manage state and avoid potential issues with bindings.

While it might require some refactoring, using classes and ObservableObjects can provide more flexibility and stability for your app. Ultimately, the choice between struct/Binding and class/ObservableObject depends on your app's requirements and how you need to manage data and state changes.

  • Thanks for this reply.

Add a Comment