Realm ObjC & Swift 2.6: 非同期にRealmを開くオプション・起動時に自動コンパクションの追加、不具合の修正

Realm Objective‑CおよびRealm Swift 2.6をリリースしました。 このバージョンには新機能として非同期にRealmを開くオプション、同期されたRealmを扱う際のユーザーオブジェクトに管理者(Admin)を示すプロパティの追加、起動時に自動的にファイルサイズのコンパクションを実行する設定の追加、不具合の修正を含みます。詳しくは下記をご覧ください。

非同期にRealmファイルを開く

このリリースでは新しいAPIとして、指定したディスパッチキューで非同期にRealmファイルを開くオプションを追加しました。

この機能によりRealmファイルを開き、アクセス可能になるまでに必要な処理はすべて指定したディスパッチキューのバックグラウンドスレッドで実行されます。時間のかかるマイグレーション処理が行われる場合などに有効です。 例:

let config = Realm.Configuration(schemaVersion: 1, migrationBlock: { migration, oldSchemaVersion in
  // 時間のかかる可能性があるマイグレーション処理
})
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.
  }
}

記事の更新情報を受け取る

さらに、同期されたRealmの場合は未ダウンロードのコンテンツをローカルにすべてダウンロードするところまで行われます。

デフォルトの挙動では同期されたRealmはオフラインであってもすぐに利用可能になり、未ダウンロードのコンテンツはそのあと逐次ダウンロードされることになります。しかし、ある種のアプリにおいては最初に最新の情報を表示する必要があることもあります。そのような状況に対応するためにasyncOpenはリモートコンテンツのダウンロードを待つために使うこともできます。 例 :

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.
  }
}

UserオブジェクトにisAdminプロパティを追加

Realm Object Serverにおける管理者ユーザーを示すisAdminプロパティを{RLM}SyncUserに追加しました。

このプロパティを使うと、ユーザーがRealm Object Serverの管理者権限を持っているかどうかがわかるので、任意の同期されたRealmにアクセスするコードを書くことが非常に簡単になります。

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
  }
}

起動時に自動的にコンパクションを実行

現状のRealmのアーキテクチャではファイルサイズは増加するのみで減少することはありません。パフォーマンスと並列処理の安全性を両立するためです。なぜRealmがそのような方針をとっているのか、詳しくはドキュメントのマルチスレッドのセクションをご覧ください。

さらに、ファイルサイズを拡張させるのはコストの高いシステムコールを使用するので、それが頻繁に呼ばれることを避けるためにRealmは実行時にファイルサイズを縮小することはしません。その代わり、空き領域は自動的に再利用されます。

しかし、それでもいくつかのケースにおいては、Realmファイルが無視できない大きさに増加することがありました。そのため、このバージョンではshouldCompactOnLaunchというブロックのプロパティをRealmの設定オプションに追加しました。指定するとRealmを最初に開く際に条件に応じてコンパクションを自動的に実行できるようになります。

例:

let config = Realm.Configuration(shouldCompactOnLaunch: { totalBytes, usedBytes in
  // totalBytesはディスク上のRealmファイルの容量を示します。 (使用領域 + 空き領域)
  // usedBytesは実際に使用している領域の容量を示します。

  // ファイルサイズが100MB以上、かつ使用領域が全体の50%より少ない場合にコンパクションを実行
  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
}

具体的な実装は、一度Realmファイルのコンテンツをすべて読み込み、別の場所に最適化した状態で書き込みます。そのあと、元のファイルと置き換えるという動作になります。そのため、コンパクションはデータ容量によっては負荷のかかる処理になります。

そのため、コンパクションを実行するタイミングについてはアプリケーションに応じて慎重に決定することを推奨いたします。

別のプロセスからアクセスがあった場合は、条件を満たしていたとしてもコンパクションは実行されません。それはRealmファイルが別のプロセスからアクセスされている状態でコンパクションを安全に実行することはできないためです。

shouldCompactOnLaunchプロパティは同期されたRealmではサポートされません。コンパクションはトランザクションログを破棄してしまうためです。Realmの同期にはトランザクションログを保持する必要があるからです。

その他の改善

  • インデックス付きの文字列に対する大文字小文字を無視した検索を高速化。
  • RLMResultsの集計関数をRLMArrayに追加。
  • 未保存のListオブジェクトでも集計関数が利用可能に。

iOS 7 Support

iOS 7のサポートは可能な限り続けますが、近い将来、iOS 8以降のみのサポートにな予定です。 release.


お読みいただきありがとうございます。 Realmで素晴らしいアプリケーションを作りましょう!お困りの際はStack Overflow(日本語)Slack(日本語)Twitter(日本語)GitHub(英語)でご相談ください。