Open flowbe opened 2 years ago
Hi @flowbe,
Probably @StateRealmObject
is what you want to try.
@pavel-ship-it thanks for the answer, I didn't know about this and it fixes the crash. However, now I still get a crash when doing:
.onReceive(myObject.objectWillChange) { _ in
print("Object changed")
}
Any other way to do this with Realm?
What crash do you have? Can you show me the code?
Same crash as above: Only objects which are managed by a Realm support change notifications
The code looks like this:
struct NewMessageView: View {
@StateRealmObject var draft: Draft
init(draft: Draft? = nil) {
let draft = draft ?? Draft(messageUid: UUID().uuidString,
body: "Default body")
draft.identityId = "my_identity_id"
_draft = StateRealmObject(wrappedValue: draft)
}
var body: some View {
NavigationView {
// My view…
}
.onReceive(draft.objectWillChange) { _ in
print("ON CHANGE")
}
}
}
It looks we have a bug here, as StateRealmObject should work with unmanaged object.
Meanwhile, as a workaround, I can recommend to use managed object. If you want to separate a draft object from the saved objects you also can use a separate object type.
Hi @flowbe the issue here is that our Combine API doesn't allow observation on unmanaged objects, so if you use StateRealmObject.objectWillChange this operation is not allowed unless StateRealmObject is managed by the realm. StateRealmObject is meant to be used in a way that any changes on the object properties (unmanaged or managed), will propagate to your SwiftUI view. So a better use of this will be to have something like this
class Draft: Object {
@Persisted var messageUid: UUID
@Persisted var body: String
@Persisted var identityId: String?
init(memessageUid: UUID, body: String) {
self.messageUid = messageUid
self.body = body
}
}
struct NewMessageView: View {
@StateRealmObject var draft: Draft
init(draft: Draft? = nil) {
let draft = draft ?? Draft(messageUid: UUID().uuidString,
body: "Default body")
draft.identityId = "my_identity_id"
_draft = StateRealmObject(wrappedValue: draft)
}
var body: some View {
NavigationView {
Text("Identity: \(draft.identityId)")
TextField("Body", text: $draft.body)
}
}
}
where your elements of the SwiftUI will change if for example there are some changes in identityId or body, and the other way in case of body
Hi @dianaafanador3, thank you for the clarification. However, I needed to observe the changes using objectWillChange
to perform non-UI actions…
Basically, my code looks like this:
var body: some View {
NavigationView {
TextField("", $draft.subject)
}
.onReceive(draft.objectWillChange) { _ in
saveDraft()
}
}
If you are using iOS > 15.0, you can use .onSubmit which will be called every time you return over a SwiftUI element. If not you can use
.onChange(of: draft.body, perform: { _ in
})
to observe an specific property in the object.
For now objectWillChange
works only with managed objects, like when our observe API.
I'll take to the team if we want to extend this to unmanaged objects.
Thank you for the suggestion. However, this doesn't match what I want to achieve. For now, I had to create a copy of my class that is not a Realm object only to make observation work and then convert it to a Realm managed object when I need to save it. This is clearly not ideal so it would be nice if you decide to improve this in the future.
How frequently does the bug occur?
All the time
Description
When annotating a Realm object as
@StateObject
or@ObservedObject
, a crash happens if this object is unmanaged. If the object is not in any Realm, it would be great to still have the observation working like any other object in SwiftUI…Stacktrace & log output
Can you reproduce the bug?
Yes, always
Reproduction Steps
@StateObject
or@ObservedObject
variable with Realm Object typeVersion
10.26.0
What SDK flavour are you using?
Local Database only
Are you using encryption?
No, not using encryption
Platform OS and version(s)
iOS 15.5
Build environment
Xcode version: 13.4 Dependency manager and version: SPM