简体   繁体   中英

Realm Swift : Update an object inside a closure

For the sake of the question, here's a simple example (with a few shortcuts) :

class Foo: Object {
  dynamic var id: Int = 0
  [...]
}

class Bar: Object {
  dynamic var id: Int = 0
  dynamic var foo: Foo?

  convenience required init(data: AnyObject) {
    self.init()
    self.id = data.id as! Int

    if let foo_id = data.foo_id as? Int {
      // Function querying the remote database and returning an object
      Foo.get(foo_id) { (foo) -> Void in
        self.foo = foo // Foo object assigned, as expected
      }
    }
  }
}

If i'm doing the self.foo = foo in the closure of the get() function, i got an exception :

exception 'RLMException', reason: 'Attempting to modify object outside of a write transaction - call beginWriteTransaction on an RLMRealm instance first.'

So if i'm adding a realm.write around it, as asked by the previous exception :

...
Foo.get(foo_id) { (foo) -> Void in
  let realm = Realm(path: Realm.defaultPath)
  realm.write {
    self.foo = foo
  }
}  
...

This time I get a new one :

exception 'RLMException', reason: 'Can not add objects from a different Realm'

I'm stuck and i can't figure out what Realm is wanting from me here, the doc isn't helping.

I'm not that used to Realm, so i suppose I got something wrong on how it works, but i don't know what.

Thanks for your help

OK, so the problem is this - you're trying to open write() session when the object is not saved in Realm in the initializer itself and my guess is that the framework is not really happy about it.

My recommendation for the approach is this:

  1. Set the values that you know before obtaining the data from the database in the object and the rest that you don't set either to some default values or set them as optional values.
  2. Save the object to the realm and then invoke the download in closure (asynchronously of course) - which will take the object in the closure and because by that time the object will have been saved in realm, you will be able to directly access savedObject.realm and you will be able to write correctly without exceptions.

tl;dr; you can't assign a persisted Realm object to a property of an unpersisted Realm object

It would be useful to know what Foo.get(_:) is doing. My guess would be that it creates a persisted Realm object (perhaps even on a different thread), whereas the Bar object is never persisted (calling super.init() will just create a standalone object, unlinked to any Realm).

If my assumptions about Foo.get(_:) are correct, just create a standalone Foo in that function instead. Then you'll be able to set it as Bar 's property outside of any write transaction.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM