Hey, I've been searching for a while now but without any luck, I post this question in the hope that someone has a brilliant idea :)
I am using TCA + SwiftUI, and the State gets initialised with a Realm object, that object is being written somewhere else and when that happens the object that I hold on my state also gets updated, so far so good, the problem is reacting to those changes in order to trigger a View update. I can subscribe to the realm object changes but I have no idea on what to trigger on the Reducer that could trigger an update on the View since I already have the latest Realm object.
Hey, the problem is that normal Realm object is live object - instance of an Object class, so it acts more like a container. The default implementation of Equatable in the Object class calls NSObject's isEqual.
From the docu:
Equality comparison is implemented by isEqual(_:)
. If the object type
is defined with a primary key, isEqual(_:)
behaves identically to this
method. If the object type is not defined with a primary key,
isEqual(_:)
uses the NSObject
behavior of comparing object identity.
This method can be used to compare two objects for database equality
whether or not their object type defines a primary key.
And SwiftUI and TCA use Equatable in order to know when to reload the view. So it won't refresh the view because the objects seem to be equal.
So you have 3 options.
- Use frozen objects as mentioned here:
Realm Object isEqual(_:) override · Issue #7781 · realm/realm-swift · GitHub
For instance you can get frozen objects by calling this method:
public func valuePublisher<T: Object>(_ object: T, keyPaths: [String]? = nil) -> RealmPublishers.Value<T>
.
OR
- Override the isEqual method of your object and compare the properties you desire. That is safe according to the link I sent in 1), since Realm doesn't use the method internally.
OR
- Create a struct wrapper that conforms to Equatable. Hold it in the state and update it everytime the realm object gets updated.
class MyObject: Object {
@Persisted(primaryKey: true) public var id: String = ""
let foo: String = ""
let moo: Bool = false
}
extension MyObject {
func toMyStruct() -> MyStruct {
MyStruct(id: id, foo: foo, moo: moo)
}
}
struct MyStruct: Equatable {
let id: String
let foo: String
let moo: Bool
}
I'd try 1) then 3) and 2). Let me know if it helped or send some code please and we can try to figure it out together.