Search code examples
iosswiftmultithreadingrealm

Can I make realm.writes directly in the Object data model?


I'm writing an app using Realm data persistence of certain objects.

In an attempt to clean up/remodel my code (getting realm.writes out of the Views and Controllers), I tried to put them directly in the persisted object class.

The logic is basically this:

class PersistedObject: Object {
   public var data: String {
      get { _saved_data }
      set {
         do { try realm?.write { _saved_data = newValue }
         } catch { print(error) }
      }
   }

   @objc dynamic private var _saved_data = "hello there"
}

This way, I'd be able to access and rewrite realm object properties from view controllers, without needing realm.writes directly in there. That's the idea, anyway.

This works sometimes. Other times, the app crashes with the error...

"Realm accessed from incorrect thread"

...which is what I'm currently trying to solve.

This is my first iOS app and my first time using Realm.

  1. Does it make sense to organize the code like this (I've found little in terms of support in this approach, but also generally little at all, in terms of MVC best-practices when working with Realm)

  2. If it does make sense, how can I solve the problem with accessing Realm from the incorrect thread, while still doing the realm.writes directly in the object class?

Thanks in advance! :) Simon


Solution

  • You're not going to want to do that.

    There's no reason not to realm.write whenever you want to write to realm - that's what it's there for. This pattern works:

    // Use them like regular Swift objects
    let myDog = Dog()
    myDog.name = "Rex"
    myDog.age = 1
    
    // Get the default Realm
    let realm = try! Realm()
    
    // Persist your data easily
    try! realm.write {
        realm.add(myDog)
    }
    

    Obviously there should be better error catching in the above code.

    Another downside is if you want to write 10 objects, they are written as soon as the data property is set - what if there are three vars you want to set and heep in memory before writing it? e.g. your user is creating a list of items in your app - if the user decides not to do that and hit's Cancel, you would then have to hit the database again to delete the object(s).

    Consider a case where you want to write 10 objects 'at the same time'?

    realm.add([obj0, obj1, obj2...])
    

    is a lot cleaner.

    Another issue comes up if you want to guarantee objects are written within a transaction - either it all succeeds or all fails. That can't be done with your current object.

    The last issue is that often you'll want to instantiate an object and add some data to it, populating the object before writing to realm. With the code in the question, you're writing it as soon as data is populated. You would have to add that same code to every property.