Realm ObjC & Swift 2.6: Async Open Realm, Admin Flag, Compact On Launch & Bug Fixes!

We’re releasing version 2.6 of Realm Objective‑C and Realm Swift today. In this release, we’re introducing powerful new APIs to asynchronously open Realms, retrieve the administrative status of Sync Users, compact Realms on first access and applying a few bug fixes to keep your apps running strong.

Asynchronously Open Realms

This release introduces an API to asynchronously open a Realm and deliver it to a block on a given queue.

This performs all work needed to get the Realm to a usable state (such as running potentially time-consuming migrations) on a background thread before dispatching to the given queue. For example:

let config = Realm.Configuration(schemaVersion: 1, migrationBlock: { migration, oldSchemaVersion in
  // potentially lengthy data migration
})
Realm.asyncOpen(configuration: config) { realm, error in
  if let realm = realm {
    // Realm successfully opened, with migration applied on background thread
  } else if let error = error {
    // Handle error that occurred while opening the Realm.
  }
}

Get more development news like this

In addition, synchronized Realms wait for all remote content available at the time the operation began to be downloaded and available locally.

The default behavior for synchronized Realms is to provide instant access, even when offline, and to incrementally sync data from the Realm Object Server. However, some apps benefit from having the latest state available before presenting it in the UI or performing some operation. For these situations, you may use the asyncOpen method to be vended a Realm only when it has been completely downloaded. For example:

let config = Realm.Configuration(syncConfiguration: SyncConfiguration(user: user, realmURL: realmURL))
Realm.asyncOpen(configuration: config) { realm, error in
  if let realm = realm {
    // Realm successfully opened, with all remote data available
  } else if let error = error {
    // Handle error that occurred while opening or downloading the contents of the Realm.
  }
}

Sync User isAdmin property

{RLM}SyncUser now has an isAdmin property indicating whether the user is a Realm Object Server administrator.

Exposing this information makes it easier for you to write code that can manipulate arbitrary synchronized Realms since you can authoritatively determine if a user has administrative access to all Realms on a Realm Object Server instance.

For example:

SyncUser.logIn(with: .usernamePassword(username: "admin", password: "💯secure"),
               server: serverURL) { user, error in
  if let user = user {
    // can now open a synchronized Realm with this user
    // true if the user is an administrator on the ROS instance
    user.isAdmin == true
  } else if let error = error {
    // handle error
  }
}

Compact On Launch

Realm’s architecture means that file sizes are always larger than the latest state of the data it contains. See our docs on Threading for some of the reasons why this architecture enables some of Realm’s great performance, concurrency and safety advantages.

Additionally, to avoid making expensive system calls to expand the size of a file very frequently, Realm files generally aren’t shrunk at runtime, instead growing by distinct size increments, and new data being written within the free space tracked inside the file.

However, there are cases in which a significant portion of a Realm file is comprised of free space. So this release adds a shouldCompactOnLaunch block property to a Realm’s configuration object to determine if the Realm should be compacted before being returned. For example:

let config = Realm.Configuration(shouldCompactOnLaunch: { totalBytes, usedBytes in
  // totalBytes refers to the size of the file on disk in bytes (data + free space)
  // usedBytes refers to the number of bytes used by data in the file

  // Compact if the file is over 100MB in size and less than 50% 'used'
  let oneHundredMB = 100 * 1024 * 1024
  return (totalBytes > oneHundredMB) && (Double(usedBytes) / Double(totalBytes)) < 0.5
})
do {
  // Realm is compacted on the first open if the configuration block conditions were met.
  let realm = try Realm(configuration: config)
} catch {
  // handle error compacting or opening Realm
}

Under the hood, the compaction operation reads the entire contents of the Realm file, rewrites it to a new file at a different location, then replaces the original file. Depending on the amount of data in a file, this may be an expensive operation.

We encourage you to experiment with the numbers to identify a good balance between performing the compaction too often and letting Realm files grow too large.

Finally, if another process is accessing the Realm, compaction will be skipped even if the configuration block’s conditions were met. That’s because compaction cannot be safely performed while a Realm is being accessed.

Setting a shouldCompactOnLaunch block is not supported for synchronized Realms. This is because compaction doesn’t preserve transaction logs, which must be kept for synchronization.

Other Enhancements

  • Speed up case-insensitive queries on indexed string properties.
  • Add RLMResults’s collection aggregate methods to RLMArray.
  • Add support for calling the aggregate methods on unmanaged Lists.

Bug Fixes

  • Fix a deadlock when multiple processes open a Realm at the same time.
  • Fix value(forKey:)/value(forKeyPath:) returning incorrect values for List properties.

iOS 7 Support

We will continue to support a minimum target iOS version of 7.0 as long as we can, but will be increasing the minimum target iOS version to 8.0 in a future release.


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