0

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?

Clifton Labrum
  • 13,053
  • 9
  • 65
  • 128

1 Answers1

1

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.

jpsim
  • 14,329
  • 6
  • 51
  • 68
  • Great answer, thank you. So can I get around this entire issue just by making the realm globally writable? I'm not concerned about the security implications of that because my application will not provide any mechanism for writing to the realm. – Clifton Labrum Aug 08 '17 at 20:37
  • Yes, you wouldn't have this issue if the Realm was globally writable, but I'd like to think that the solution I outlined wouldn't be so burdensome as to sacrifice your access control model, but that's your call. – jpsim Aug 08 '17 at 20:40
  • Hmm... so are you saying that after this `/shared` realm is initialized with `asyncOpen`, I can still listen for changes with a `NotificationToken` and interact with it like any normal realm? I would only need `asyncOpen` again to get schema changes? – Clifton Labrum Aug 08 '17 at 20:57
  • Yes to your first question. No to your second. You'd use `asyncOpen` if you'd want to not block the current thread and be notified when your locally synced copy "catches up" to the latest state on the server. – jpsim Aug 08 '17 at 21:34
  • If schema changes are made to the Realm on ROS while you're accessing it synchronously locally, those schema changes will be synced down to you even if you never call `asyncOpen` again. – jpsim Aug 08 '17 at 21:34
  • Thank you very much, @jpsim, for your thorough replies and your attentiveness. :) – Clifton Labrum Aug 08 '17 at 23:26
  • Happy to help!! – jpsim Aug 09 '17 at 03:30