1

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.

Small Talk
  • 747
  • 1
  • 6
  • 15
  • If you look at the documentation for state it will tell you that it is for changes in value. A class can trigger an update if you replace it but not if you change the variables because the variables don’t change its value. – lorem ipsum Sep 26 '22 at 00:39
  • Thanks for response! While I didn't see anything explicit in the docs about requiring use of Value types only, the State generic is presented as an inout parameter. This certainly suggests that a value-type is expected. My takeaway from your comment and the docs is that any and all State MUST be a a value-type in order for UI updates to work. And that even using `@ObservedObjects` as State will fail to the update the UI when modified in a (`ReducerProtocol`) `reduce` method. – Small Talk Sep 26 '22 at 12:51
  • I didn't say that is must be a value-type, I said that `State` only updates when the value changes. You can use reference but it will only trigger changes when you replace it. – lorem ipsum Sep 26 '22 at 13:14

0 Answers0