Realm.write in .onDisappear

I have a list in my app that is using @ObservedRealmObject. This allows the .move() and .remove() functions to work perfectly.

I was also using a straight binding for the strings, but I ran into a potential performance/server issue.

I have a trigger that updates some other data when a user updates their object. I don’t want that to fire on every single keystroke, so my idea was to map the string props to state during .onAppear() and then write those back to Realm during .onDisappear().

Simplified version here:

.onAppear(perform: {
  self.title = self.task.title
}
.onDisappear(perform: {
  if self.title != self.task.title {
    do {
      try! userRealm.write {
        task.title = self.title
      }
    }
  }
})

When this runs, I receive an error:

Terminating app due to uncaught exception ‘RLMException’, reason: ‘Attempting to modify object outside of a write transaction - call beginWriteTransaction on an RLMRealm instance first.’

Obviously I am using a write transaction, so this error is very confusing.

It may be helpful to note that task in this example is an EmbeddedObject. I sometimes run into a situation where it seems to not be sure of the exact object to update, so I also tried this:

.onAppear(perform: {
  self.title = self.task.title
}
.onDisappear(perform: {
  if self.title != self.task.title {
    if let taskToUpdate = parentObject.tasks.filter("_id = %@", task._id).first {
      do {
        try! userRealm.write {
          taskToUpdate.title = self.title
        }
      }
    }
  }
})

I get the same error when I try this.

Does anyone know if there is something weird with .onDisappear() that since the View is being closed that maybe the Realm is no longer accessible or something?

I’m definitely open to other creative ways to solve this issue, but also just want to understand what is happening in .onDisappear() with regard to Realm so that I can use it when appropriate.

Hey Kurt. I believe this is due to a lack of documentation on our part. @ObservedRealmObject uses frozen objects. So to do your write, the code needs to be:

  if self.title != self.task.title {
      guard let task = self.task.thaw(), let realm = task.realm else {
            return
      }
      try! realm.write {
        task.title = self.title
      }
    }
  }
1 Like

Totally worked. Thanks Jason!