Search code examples
realmrealm-mobile-platformrealm-object-server

How Are Objects Synced in a Shared Realm in Swift


After scouring the documentation, I recently learned that a shared realm (globally available to all users of my app) can only be queried with Realm.asyncOpen. For example, I have a /shared realm that has read-only access to any user. I tried querying it in the usual way, but it returned zero objects. But if I query it like this, it works:

Realm.asyncOpen(configuration: sharedConfig) { realm, error in
  if let realm = realm {
    // Realm successfully opened
    self.announcements = realm.objects(Announcement.self)

    print(self.announcements)
    self.tableView.reloadData()

  } else if let error = error {
    print(error)
  }
}

This method is visibly slower than a usual realm query since it appears to be fetching the data from the server instead of a local, already-synced realm.

Does this mean that the objects pulled down are never stored in the local copy of the realm, but are queried from the ROS each time I access them?

In other words, are shared realms pulled and not synced?


Solution

  • a shared realm (globally available to all users of my app) can only be queried with Realm.asyncOpen

    This is incorrect. If a user only has read-only access to a Realm, it must be obtained with Realm.asyncOpen. That's explicitly what the documentation you linked to states.

    This method is visibly slower than a usual realm query since it appears to be fetching the data from the server instead of a local, already-synced realm.

    Almost correct. Yes data is fetched from the server, but not the whole Realm from scratch. Only the new data since the last time the Realm was synced with your local copy.

    Does this mean that the objects pulled down are never stored in the local copy of the realm, but are queried from the ROS each time I access them?

    This synced Realm is persisted locally and will be preserved across application launches.

    In other words, are shared realms pulled and not synced?

    No.


    Taking a step back, let's explain what's happening here.

    The reason why you get a "permission denied" error if you attempt to open a read-only synced Realm synchronously is that upon initialization, a local Realm file will be created, performing write operations to write the Realm's schema (i.e. create db tables, columns & metadata) immediately. However, since the user does not have write access to the Realm, the Realm Object Server (ROS) rejects the changes and triggers your global error handler notifying you that an illegal attempt to modify the file was made by your user.

    The reason why this doesn't happen with asyncOpen is that it's an asynchronous operation and therefore doesn't need to give you a valid Realm immediately, so it doesn't need to "bootstrap" it by writing the schema to it. Instead, it requests the latest state of the Realm from ROS and vends it back to you once it's fully available in its latest state at the point in time at which the call was started.

    That being said, if the local copy of the Realm already has its schema initialized (i.e. after a successful asyncOpen call), and the in-memory schema defined by either the default schema or the custom object types specified in Realm.Configuration hasn't changed, then no schema will be attempted to be written to the file.

    This means that any time after a successful asyncOpen call, the Realm could be accessed synchronously without going through asyncOpen as long as you're ok with potentially not having the most up to date data from ROS.

    So in your case, it appears as though you only want to use asyncOpen for the very first access to the Realm, so you could persist that state (using another Realm, or NSUserDefaults) and check for it to determine whether or not to open the Realm the asynchronously or synchronously.