1

Learning how to use Realm Mobile Platform.

I built a small iOS app which successfully saves data to a server and the data is consistent across different devices. The app is very similar to the official realm tutorial.

I can open the Sync URL from the Realm Browser Mac Application and I see the changes happening fine in real time. This is where I'm stuck: I am trying to see the changes in the local realm file, but

print(self.realm.configuration.fileURL) returns nil print(Realm.Configuration.defaultConfiguration.fileURL) is an empty file

This is my code:

SyncUser.logIn(with: cloudKitCredentials, server: serverURL) { user, error in
    guard let user = user else {
        fatalError(String(describing: error))
    }

    DispatchQueue.main.async {
        // Open Realm
        let configuration = Realm.Configuration(
            syncConfiguration: SyncConfiguration(
                user: user,
                realmURL: URL(string: "realm://myIPaddress/~/realmtasks")!)
            )

        self.realm = try! Realm(configuration: configuration)

        // Show initial tasks
        func updateList() {
            self.items = Array(self.realm.objects(Row.self))
            self.tableView.reloadData()
        }

        updateList()

        print(self.realm.configuration.fileURL) 
        //returns nil

        print(Realm.Configuration.defaultConfiguration.fileURL) 
        // I can open the file, but it's empty

        // Notify us when Realm changes
        self.notificationToken = self.realm.addNotificationBlock { _ in
            updateList()
        }
}

The reason I'm testing this, is so that I can load the data from the file instead of from the server. So that: (a) login will only be called once (b) data is available when the user is offline.

  • Can you provide details about the crash? ie, how to reproduce it, etc? Obviously, sync cannot happen when the device is offline, however, you still have access to the data that was synchronised *before* being offline. The app needs to be online when doing the initial user authentication. – teotwaki Feb 27 '17 at 10:33
  • @teotwaki I seem to have not worded my question properly. Sorry for that. To rephrase: I was under the impression that using ROS will create a mirrored on-disk realm file. Upon further experimenting, I created a realm file that will reside on the device, and then push the changes to another realm file on the server whenever a change happens. The realm on the server is for back-up purposes, while the on-disk file is the primary offline one. I am not sure if this is good/bad practice, but I will post my experiment once done to get feedback. Many thanks for your reply. – j_theislander Feb 27 '17 at 11:36
  • There is no concept of a "Realm on the server". You always work on a local file, even for queries/modifications. If the file is sync-enabled, its history gets replicated on the server, which allows other clients to download the history and re-assemble the Realm locally. You're essentially doing the same thing that ROS provides manually. – teotwaki Feb 27 '17 at 11:43
  • Ok! Aborting my experiment. Will be testing again tomorrow. Is the file sync-enabled by default? – j_theislander Feb 27 '17 at 11:55
  • It is if you open the Realm with a `syncURL`. – teotwaki Feb 27 '17 at 11:55
  • The default.realm remains empty. I re-worded my original question in a way that makes more sense - I think. – j_theislander Feb 28 '17 at 07:26

1 Answers1

1

When you login for the first time Realm automatically stores the user in the keychain. You can then retrieve it via SyncUser.currentUser property and use it to open your realm even if you're offline. However if you log out the user then you won't be able to use it offline.

realm.configuration.fileURL is not available when using syncConfiguration.


For this case:

  1. Call SyncUser.logIn only once
  2. For normal app runs (i.e all runs except the initial run), open the realm with the same configuration.

You should have something like this:

// First launch
if launchedBefore == false {
    setupRealm()

// All other launches
} else if launchedBefore == true {
    let user = SyncUser.current!
    openRealm(forUser: user)
}

openRealm(forUser: SyncUser) is basically the same as the whole dispatch block from the previous code.

setupRealm()can call it too to clean up the code:

SyncUser.logIn(with: cloudKitCredentials, server: serverURL) { user, error in
    guard let user = user else {
        fatalError(String(describing: error))
    }

    self.openRealm(forUser: user)
}
Dmitry
  • 7,300
  • 6
  • 32
  • 55
  • Sorry I'm not quite following. Currently the `default.realm` is empty. Does it get populated automatically _after_ I use `SyncUser.currentUser`? And what is the proper way of opening it in this case? – j_theislander Feb 28 '17 at 11:52
  • @Jalal you're specifying a URI for the Realm you're opening, so the filename will be different than `default.realm`. `default.realm` is only used when you use the default constructor (ie: `let realm = Realm()`). Please note that when opening a sync'd Realm, the location of the local file is hidden from you. You should not attempt to access it manually. – teotwaki Feb 28 '17 at 12:31
  • @teotwaki Wow thanks! Your comment helped me in seeing how my testing approach was wrong. – j_theislander Mar 01 '17 at 08:41