TCA: Using a reference-type property within a State struct fails to drive UI updates

752 views Asked by At

Below is simplified State for a TCA App. (Assume the rest of the stack is compiling.)

//PROBLEM: When Dog is a Class, instead of a Struct, changes to the dog name property made in the Reducer fail to update the UI

class Dog: Equatable {
    
    var name = "Spot"
    
    //Equatable conformance
     static func == (lhs: Dog, rhs: Dog) -> Bool {
           lhs.name == rhs.name
        }
    }
    
    struct DogManager: ReducerProtocol {

         struct State {
         var dog = Dog()
         }
     }

//Action enum and reduce method omitted
    }

The question is why UI updates are not made when state changes are made in the reduce method to the dog property.

//in the 'reduce' method of a ReducerProtocol-conforming Struct


case .changeDogName: state.dog.name = "Fido"

//changing the property 'dog.name' (assuming 'dog' is a reference-type object) 
//does *not* trigger view updates

Even when the Dog class is decorated with ObservableObject and the name property with the @Published property-wrapper, UI updates do not occur when dog.name is modified in the reduce method.

I understand the TCA library encourages us to put everything State-related into a Struct. But is it possible at all to use reference-type properties, and have SwiftUI updates work properly?

I know there are workarounds:

  1. Make Dog a Struct, instead of a Class. Then everything works as expected.
  2. Add Dog into a ReducerProtocol-conforming Struct as a separate ObservedObject property. Then UI updates also work as expected.

I'm just curious why UI updates don't work when a reference type is added as a property in a State struct, and then modified by the reducer. I would have thought that Equatable conformance by a Class would be sufficient to trigger view updates.

0

There are 0 answers