Realm Blog

Realm Objective‑C & Swift 0.99 – Fine-Grained Notifications!

Realm Objective‑CおよびRealm Swift 0.99をリリースしました。

このバージョンには、2年前のRealmのリリース当時から非常に多くのリクエストをいただいていた、Fine-grained change notifications(きめ細やかな変更通知)が含まれています。

また、Objective-CとSwift双方のAPIをすべて見直し、重複や不要になったAPIを洗い出しました。そのため少しの非互換の変更が含まれます。APIをよりわかりやすく一貫性のあるものにするための措置ですのでご了承ください。

Fine-Grained Notifications(きめ細やかな変更通知)

このバージョンではコレクションに対する変更通知(Realm 0.98で導入されました)を改善し、新しくchangesパラメータが通知ブロックに渡されるようになりました。

このRLMCollectionChange/RealmCollectionChange型のパラメータは、何が変更されたのかを示します。1つ前に通知を受けたときから追加、削除、および変更されたオブジェクトのインデックスが格納されています。これまでは通知のタイミングでただすべてを再読み込みするしかありませんでしたが、この改善により、よりきめ細やかなアニメーションや表示を伴ったUIの更新を行うことができます。

インデックスの配列はUITableViewの更新APIの規約に従っており、インデックスパスに変換するだけでテーブルビューを更新するメソッドにそのまま渡すことができます。下記はテーブルビューを更新する例です。

Fine-Grained Notifications

例えば、セクションが1つのテーブルビューの場合は、次のように書けばいいです。

notificationToken = results.addNotificationBlock { changes
  switch changes {
  case .Initial:
    // この時点でクエリは実行済みのため、ResultsへのアクセスはUIをブロックしません
    self.tableView.reloadData()
    break
  case .Update(_, let deletions, let insertions, let modifications):
    // Resultsに変更があったので、UITableViewに変更を適用します
    self.tableView.beginUpdates()
    self.tableView.insertRowsAtIndexPaths(insertions.map { NSIndexPath(forRow: $0, inSection: 0) },
        withRowAnimation: .Automatic)
    self.tableView.deleteRowsAtIndexPaths(deletions.map { NSIndexPath(forRow: $0, inSection: 0) },
        withRowAnimation: .Automatic)
    self.tableView.reloadRowsAtIndexPaths(modifications.map { NSIndexPath(forRow: $0, inSection: 0) },
        withRowAnimation: .Automatic)
    self.tableView.endUpdates()
    break
  case .Error(let error):
    // バックグラウンドのワーカースレッドがRealmファイルを開く際にエラーが起きました
    fatalError("\(error)")
    break
  }
}
__weak typeof(self) weakSelf = self;
self.notificationToken = [[Person objectsWhere:@"age > 5"] addNotificationBlock:^(RLMResults<Person *> *results, RLMCollectionChange *change, NSError *error) {
  if (error) {
    NSLog(@"Failed to open Realm on background worker: %@", error);
    return;
  }

  UITableView *tableView = weakSelf.tableView;
  // 初回の通知ではchangeパラメータはnilになります
  if (!changes) {
    [tableView reloadData];
    return;
  }

  // Resultsに変更があったので、UITableViewに変更を適用します
  [tableView beginUpdates];
  [tableView deleteRowsAtIndexPaths:[changes deletionsInSection:0]
                   withRowAnimation:UITableViewRowAnimationAutomatic];
  [tableView insertRowsAtIndexPaths:[changes insertionsInSection:0]
                   withRowAnimation:UITableViewRowAnimationAutomatic];
  [tableView reloadRowsAtIndexPaths:[changes modificationsInSection:0]
                   withRowAnimation:UITableViewRowAnimationAutomatic];
  [tableView endUpdates];
}];

詳しくはドキュメントのコレクションの変更に対する通知をご覧ください。

APIの変更

時間をかけてRealmに機能を追加してきたので、整合性のためにAPI全体を見直しました。

変更点は下記のカテゴリに分類されます。

  1. RLMNotificationToken/NotificationTokenの通知を解除するメソッドは-stopだけになりました。
  2. encryptionKeyパラメータを取るメソッドと取らないメソッドがありましたが、取るメソッドに統合されました。
  3. RLMRealm/RealmRLMRealmConfiguration/Realm.Configurationの両方に存在するプロパティはConfigurationクラスのプロパティに統合されました。Realm側のプロパティは非推奨になります。
  4. これまで文字列で渡していたファイルパスの引数とプロパティはNSURL型に変更されました。これは今後のアップルの標準APIに沿うためのものです。
  5. Swift 2への移行時に変更し忘れていて、NSErrorPointerを使用するAPIを、Swift標準のエラーハンドリング(throws)を使うように修正しました。

下記の表はObjective-CのAPIにおける、非推奨のメソッドと代替メソッドの対応表です。

Deprecated API New API
-[RLMRealm removeNotification:] -[RLMNotificationToken stop]
RLMRealmConfiguration.path RLMRealmConfiguration.fileURL
RLMRealm.path RLMRealmConfiguration.fileURL
RLMRealm.readOnly RLMRealmConfiguration.readOnly
+[RLMRealm realmWithPath:] +[RLMRealm realmWithURL:]
+[RLMRealm writeCopyToPath:error:] +[RLMRealm writeCopyToURL:encryptionKey:error:]
+[RLMRealm writeCopyToPath:encryptionKey:error:] +[RLMRealm writeCopyToURL:encryptionKey:error:]
+[RLMRealm schemaVersionAtPath:error:] +[RLMRealm schemaVersionAtURL:encryptionKey:error:]
+[RLMRealm schemaVersionAtPath:encryptionKey:error:] +[RLMRealm schemaVersionAtURL:encryptionKey:error:]

下記の表はSwiftのAPIにおける、非推奨のメソッドと代替メソッドの対応表です。

Deprecated API New API
Realm.removeNotification(_:) NotificationToken.stop()
Realm.Configuration.path Realm.Configuration.fileURL
Realm.path Realm.Configuration.fileURL
Realm.readOnly Realm.Configuration.readOnly
Realm.writeCopyToPath(_:encryptionKey:) Realm.writeCopyToURL(_:encryptionKey:)
schemaVersionAtPath(_:encryptionKey:error:) schemaVersionAtURL(_:encryptionKey:)

その他の非互換の変更

  • id/AnyObject型のプロパティは非推奨になりました。ほとんど利用されておらず、便利であるユースケースも少ないことと、他のプラットフォームで未サポートであることが理由です。
  • -[RLMArray addNotificationBlock:]-[RLMResults addNotificationBlock:]のブロックは今回から追加のパラメータをとるように変更されました。先述のFine-Grained Notificationsに関する変更です。

不具合の修正

  • RLMObjectのAssociated objectのdeallocメソッドで通知を解除していた場合に解放済みのオブジェクトにアクセスしてしまう問題を修正しました。
  • Realmファイルをオープンする際のわずかなメモリリークを修正しました。
  • Realmの初期化、およびコミット時に十分なメモリ空間を確保できないときに、クラッシュするのではなくRLMErrorAddressSpaceExhaustedエラーを返すように変更しました。

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


Realm Team

At Realm, our mission is to help developers build better apps faster. We provide a unique set of tools and platform technologies designed to make it easy for developers to build apps with sophisticated, powerful features — things like realtime collaboration, augmented reality, live data synchronization, offline experiences, messaging, and more.

Everything we build is developed with an eye toward enabling developers for what we believe the mobile internet evolves into — an open network of billions of users and trillions of devices, and realtime interactivity across them all.

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