Optimizing SwiftUI with custom diffing when using @ObservedObject

I'm following the steps in this article to improve SwiftUI performance with custom diffing. For now, I'm just returning true in ==:

struct MyView: View, Equatable {
   
   @ObservedObject var model: DataModel
   
   static func == (lhs: Self, rhs: Self) -> Bool {
       return true
   }

   var body: some View { ... lots of stuff ... }

}

I'm using .equatable() to wrap MyView in EquatableView where it's used.

However in the SwiftUI instrument, I still see the entire view rebuilt whenever DataModel changes. And the debugger confirms that body is called. == is also called.

It would seem that customizing diffing can't be used with @ObservedObject. When I remove the @ObservedObject, body isn't called. But without @ObservedObject, I can't bind the UI within my view to my data model (similar issue for @EnvironmentObject).

Anyone know how to accomplish this? thanks!

I ended up creating another ObservableObject which only stores the information I need:

class MyViewModel: ObservableObject {
    
    var dataModel: DataModel
    var uiSub: Any!
    
    @Published var someState = 0 {
        didSet {
            dataModel.someStruct.someState
        }
    }
    
    init(model: DataModel) {
        self.dataModel = model
        someState = model.someStruct.someState
        
        uiSub = model.$someStruct.sink { [weak self] someStruct in
            guard let self = self else { return }
            if someStruct.someState != self.someState {
                self.someState = someStruct.someState
            }
        }
    }
}

So changing say model.someStruct.someOtherField wouldn't trigger any changes to MyViewModel.

This approach isn't terribly satisfying, but at least I don't have to change my DataModel to optimize SwiftUI. Anyone know a better way?

Terms of Service

Privacy Policy

Cookie Policy