Realm ObjC & Swift 2.3: Sync Progress Notifications, Improved Sharing & Backup Recovery!

We’re releasing version 2.3 of Realm Objective‑C and Realm Swift today, which includes several improvements to the Realm Mobile Platform features, such as sync progress notifications, backup recovery, and more flexible sharing mechanisms. Read on to learn more!

Sync Progress Notifications

Realm Mobile Platform offers a true offline-first experience, where changes can be applied immediately to the local Realm irrelevant of the network conditions. In the background, the synchronization happens automatically, and when the network is available, changes quickly propagate across devices and the server. This enables the realtime, collaborative experiences unique to Realm.

There are times, however, when it’s useful to know how much data is left to transfer. Perhaps on the first launch of your app, you’d like to make sure a sizable amount of the data is available before presenting your user interface. At other times, your app would simply benefit from showing when data is synchronizing, by presenting a progress bar or activity indicator.

This is why we’ve added APIs to monitor sync progress by registering notification blocks on SyncSession. Simply, specify the transfer direction (.upload/.download) and mode (.reportIndefinitely/.forCurrentlyOutstandingWork) to monitor.

For example, to show an upload progress bar after writing a large image to your Realm and waiting for it to upload, you might write this:

let session = SyncUser.current.session(for: realmURL)!
self.token = session.addProgressNotification(for: .upload,
                                             mode: .forCurrentlyOutstandingWork) { progress in
  self.updateProgressBar(fraction: progress.fractionTransferred)
  if progress.isTransferComplete {
    self.hideProgressBar()
    self.token.stop()
  }
}

Or to show an activity indicator for the entire lifetime of your app, you might write this:

let session = SyncUser.current.session(for: realmURL)!
self.token = session.addProgressNotification(for: .download,
                                             mode: .reportIndefinitely) { progress in
  if progress.isTransferComplete {
    self.hideActivityIndicator()
  } else {
    self.showActivityIndicator()
  }
}

Flexible Sharing Mechanism

Realtime collaboration and data sharing is an important pillar of the Realm Mobile Platform. To enable this, we made it possible for mobile developers to share Realms between users when we introduced the PermissionChange APIs in November.

Today, we’re making it even easier to share Realms between users, allowing extremely flexible sharing and permission management, all controlled from the Realm client APIs and without the need to write any server code! Specifically, we’re adding the SyncPermissionOffer and SyncPermissionOfferResponse classes to allow creating and accepting permission change events for synchronized Realms between different users.

These APIs once again demonstrate the power of the Realm Mobile Platform’s objects-as-APIs approach. Making and receiving permission offers is very similar to the existing PermissionChange process. Simply create the object in the current user’s management Realm and observe it to know when it was synchronized and processed by the Realm Object Server.

Sharing a synchronized Realm is as easy as following these steps:

  1. Create a SyncPermissionOffer object in the user’s management Realm.
  2. Wait for the offer to be synced and processed by the server.
  3. Once the token property of the object is populated, send it to another user however you’d like: email, iMessage, Action Controller, carrier pigeon, whatever you like!
  4. The receiving user then creates a SyncPermissionOfferResponse object in his/her management Realm.
  5. The receiving user then waits for the response to be synced and processed by the server.
  6. Once the response has been processed, the receiving user can now access the Realm at the response’s realmUrl property.

For example:

////////////////
// Sender
////////////////

// Create offer with full permissions
let shareOffer = SyncPermissionOffer(realmURL: realmURL, expiresAt: nil,
                                     mayRead: true, mayWrite: true, mayManage: true)
// Add to management Realm to sync with ROS
try managementRealm.write {
  managementRealm.add(shareOffer)
}
// Wait for server to process
let offerResults = managementRealm.objects(SyncPermissionOffer.self).filter("id = %@", shareOffer.id)
shareOfferNotificationToken = offerResults.addNotificationBlock { _ in
  guard case let offer = offerResults.first,
             offer.status == .success,
             let token = offer.token else {
    return
  }
  // Send token via UIActivityViewController
  let url = "realmtasks://" + token.replacingOccurrences(of: ":", with: "/")
  let activityViewController = UIActivityViewController(activityItems: [url], applicationActivities: nil)
  self.present(activityViewController, animated: true, completion: nil)
}

////////////////
// Receiver
////////////////

// Create response with received token
let response = SyncPermissionOfferResponse(token: token)
try managementRealm.write {
  managementRealm.add(response)
}
// Wait for server to process
let responseResults = managementRealm.objects(SyncPermissionOfferResponse.self).filter("id = %@", response.id)
acceptShareNotificationToken = responseResults.addNotificationBlock { _ in
  guard case let response = responseResults.first,
             response.status == .success,
             let realmURL = response.realmUrl else {
    return
  }
  // User can now access Realm at realmURL 🎉
}

We have a Proof-Of-Concept branch towards RealmTasks that demonstrates how sharing lists between users could be built using this mechanism.

Backup Recovery

When your servers go down, you need a plan to recover. That’s why the Realm Mobile Platform has offered the ability to back up your data for a few months now. Today we’re announcing our Continous Backup solution to automate keeping up-to-date backups.

Under normal conditions, Realm’s synchronization engine works by transferring just the specific operations. When the Realm Object Server confirms the receipt of new operations, the local logs are cleaned up. This helps keep your app’s disk usage small and Realm blazing fast ⚡️.

Furthermore, because Realm is an offline-first database, if your Realm Object Server is down for whatever reason, all your local data stays available.

However, if you need to recover from a backup on your server, your clients will receive a “client reset” error via the global error handler. Note that you may continue to use the local Realm as you normally would, but that any subsequent changes, or changes made after the last backup point, will be lost.

Once you receive a “client reset” error, you could inform the user about the situation, stop accessing the Realm and redownload the Realm from the server at the latest backed up version. The NSError’s userInfo property contains a block that you may call to clean up the previous local version of the Realm.

If you choose to not handle the client reset error immediately, the next time your app launches, the previous local version of the Realm will be deleted and redownloaded from the server at the latest backed up version automatically on first access.

Bug Fixes

  • Fix a call to commitWrite(withoutNotifying:) committing a transaction that would not have triggered a notification incorrectly skipping the next notification.
  • Fix incorrect results and crashes when conflicting object insertions are merged by the synchronization mechanism when there is a collection notification registered for that object type.

Legacy Swift Version Support

We’d like to remind you that we will continue to support Xcode 7.3.1 and Swift 2.x as long as we can, but encourage all our users to migrate to Swift 3 as soon as possible.


Thanks for reading. Now go forth and build amazing apps with Realm! As always, we’re around on Stack Overflow, GitHub, or Twitter.