Realm Blog

Realm React Native 1.0: Realm Mobile Platformに対応しました。

by /

本日はReact Nativeコミュニティのみなさまに2つのお知らせをいたします。

1つめのお知らせは、オープンソース化から約1年を経てRealm React Nativeがバージョン1.0となったことです。これは強力なオブジェクトデータベースとしての、そして素晴らしいリアクティブアプリのための基礎としての大きなマイルストーンに到達したことを意味します。そしてもう一つのお知らせは、Realm Mobile Platformのサポート対象にReact Nativeが新たに追加されたということです。Realm React Nativeを利用していただいている開発者の方々には、数行のコードの追加で、新たな機能を利用できるようになります。

昨年Realm React Nativeをベータ版としてリリースしてから今日まで、React NativeのコミュニティやTaskRabbitなどの企業にご利用いてきました。Realmはさまざまなプラットフォームで利用可能なデータベースであるため、コードの優れた再利用性と堅牢性を提供します。また、Realmのライブオブジェクトとコレクション通知は、Realm上のデータ更新に対して真にリアクティブなアプリケーションの開発を可能にします。Realmを使い始めるのはとても簡単です。詳しくはRealm React Nativeのドキュメントを参照してください。

Realmは単なるクライアントサイドで利用可能なデータベースにとどまりません。Realm React Native 1.0のリリースにともない、Realm Mobile Platformの機能を利用して強力なアプリケーションを開発可能になります。Realm Object Serverをつかってデータ同期可能なRealmを作成することで、プロパティの変更は自動的に同期されます。またこれらのデータはオフラインの際も利用できるようローカルにも保持されます。Realm Mobile Platformは単なるデータ同期だけでなく、コンフリクト解決、ユーザー認証、カスタマイズ可能なパーミッションなど複数デバイスにまたがった機能をもつアプリケーションに必要なすべての機能を提供します。

Realm Mobile Platoformのプロフェッショナル版およびエンタープライズ版では、サーバーサイドでもJavaScriptによるリアクティブなコードの記述を可能にするEvent Handling機能が提供されています。これによりコードベース全体でリアクティブ原則を取り入れることが可能になり、いつどこで発生したデータ変更に対しても反応することができます。

既存のReact NativeアプリケーションをRealm Mobile Platoformに統合するのはとても簡単です。ユーザーの認証後Realm Object Serverに接続し、アプリケーションのUIをリアクティブに更新するサンプルコードは以下のようになります。


import React, { Component } from 'react';
import { Text } from 'react-native';
import Realm from 'realm';
import { ListView } from 'realm/react-native';

export default class DogsView extends Component {
    constructor(props) {
        super(props);
        // Initialize the component with an empty data source
        const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
        this.state = { dataSource: ds };
    }

    componentWillMount() {
        // `this.props`はDogsViewでつかうusernameとpasswordを保持しています。
        Realm.Sync.User.login('https://my-realm-server.com', this.props.username, this.props.password, (error, user) => {
            let realm = new Realm({
                schema: [ { name: 'Dog', properties: { name: 'string' } } ],
                sync: { user, url: 'realms://my-realm-server.com/~/dogs'}
            });
            // ログインが完了後、同期を有効化したRealmインスタンスを作成します。
            // Realm内の全Dogオブジェクトを保持するコレクションを取得し、DataSourceを初期化するとともに
            // コレクションにセットしたリスナーでコレクション要素の更新をUIに反映します。
			const dogs = realm.objects('Dog');
            this.setState({ realm, dataSource: this.state.dataSource.cloneWithRows(dogs) });
			dogs.addListener(() => this.forceUpdate());
        });
    }

    render() {
        return (<ListView dataSource={this.state.dataSource} renderRow={(item) => <Text>{item.name}</Text>} />);
    }
}

Realm Mobile Platformを使い始めるには公式ドキュメントを参照してください。オンライン、オフラインに関わらず動作するユーザーに愛されるアプリケーションの開発を始めましょう。

Read more

Realm ObjC & Swift 2.4: オブジェクトレベルの通知

by /

Realm Objective‑CおよびRealm Swift 2.4をリリースしました。 このバージョンには新機能としてオブジェクトレベルの通知が実装されました。各オブジェクトの更新をトリガーにした処理を書くことができるようになります。詳しくは下記をご覧ください。

オブジェクトレベルの通知

オブジェクトに変更があったことを通知するには、これまではコレクションの通知を利用する必要がありました。それによって、オブジェクトの追加削除、あるいは変更されたことを通知によって知ることができます。しかし、どのプロパティが変わったのかまではわかりませんでした。また、1つのオブジェクトに対する変更を通知したいだけなのに、コレクションを作り、非同期に監視するというのは面倒で、クエリとの相性もよくありませんでした。

単一のオブジェクトに対して、プロパティの変更を通知するには、KVOを使うこともできました。しかし、今となっては KVOはかなり古臭い仕組みであり、プロパティ1つ1つに対してKVOを設定しなければなりませんし、もちろん他のプラットフォームや言語で使うことはできません。またKVOによる通知は__同期的に__動作するので、UIスレッドをブロックしてしまうこともあります🙀。

本日リリースするオブジェクトレベルの通知では、1つのオブジェクトに対する変更をとても便利に監視できます。オブジェクト通知はコレクション通知と同様に、非常にシンプルなAPIで使えます。単に監視したいオブジェクトに通知ブロックを追加するだけです。通知が作成されると、NotificationTokenが返されるので、監視している間はトークンを保持するようにします。

通知が有効になると、変更があるたびに通知ブロックが呼ばれ、structのObjectChange引数によって、どのプロパティが変わったのか、またはオブジェクトが削除されたことを知ることができます。

class Message: Object {
  dynamic var isRead = false
  dynamic var content = ""
}

class MessageController: UIViewController {
  private let notificationToken: NotificationToken

  init(message: Message) {
    notificationToken = message.addNotificationBlock { change in
      switch change {
      case .change(let properties):
        if let readChange = properties.first(where: { $0.name == "isRead" }) {
          self.showReadBadge = readChange.newValue as! Bool
        }
        if let contentChange = properties.first(where: { $0.name == "content" }) {
          self.contentView.textValue = contentChange.newValue as! String
        }
      case .deleted:
        self.handleDeletion()
      case .error(let error):
        self.handleError(error)
      }
    }
  }

  deinit {
    notificationToken.stop()
  }
}

通知を停止するには、token.stop()メソッドを呼ぶか、トークンオブジェクトを解放します。

まとめると、Realmに保存されているオブジェクトに対してaddNotificationBlockを呼び、返ってきたNotificationTokenインスタンスを監視している間は保持します。通知ブロックの中で変更に対してリアクションします。

2点注意することがあります。List型のプロパティ(関連)が変更された場合は、newValueoldValueも渡ってきませんが、通知ブロックは呼び出されます。もし同期的にUIを更新したり、通知をスキップしたい場合はrealm.commitWrite(withoutNotifying: [token])を利用してUI駆動の書き込みテクニックを使用します。

不具合の修正

同期されたRealmを利用するとき、認証トークンを更新する際のエラーハンドリングの不具合を修正しました。 上記の問題のため、Realm Mobile Platformを利用している場合は、このバージョンにできるだけアップデートするようにしてください。

数か月もの間、頭を悩ませていたレースコンディション🏎によって”bad transaction log”の例外が発生する不具合も修正されています。

Swift 2サポートの削除

古いSwiftバージョンをサポートすることは__非常に__大変です😅。現在Swift 2.xを利用している開発者の割合は5%以下に満たないため、このバージョンからSwift 2.xはサポートされません。

つまりRealm Swift 2.3.0がSwift 2.xで使える最後のバージョンになります。ご不便をおかけしますが、ご了承ください。

Xcode 8.3 Beta 1について

先週Xcode 8.3 betaがリリースされました。Realm Objective-Cにコンパイルエラーが起こる問題がありましたが、すでに修正済みです。

しかし、Swift 3.1におけるコンパイルエラーの問題がまだ残っています。こちらのIssue#4586でXcode 8.3のサポートについて進捗を報告していますのでご覧ください。


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

Read more

Realm Objective-C & Swift 2.2: スレッド間のオブジェクトを受け渡し、関連による並べ替えなどをサポート

by /

これまでのRealmの設計が目指していたもののひとつに、一貫性があり、わかりやすいスレッドモデルを提供するということがありました。このたび、Realm Objective‑CおよびRealm Swift 2.2より、安全にスレッド間をまたいでオブジェクトを受け渡すことができる仕組みを用意しました。また関連のプロパティを並べ替えに使用することがこのバージョンからできるようになりました。その他、同期に関する改善と不具合の修正が含まれます。

スレッドに従う

本日より、Realmでは複数のスレッド間でオブジェクトを扱うことがさらに簡単になりました。これまでのマルチスレッドの対応は何年もの間の絶え間ない議論の果てに下された決断で、意図的なものです(なぜなら、マルチスレッドは本質的に難しいものだからです。)。

以前に公開した、「Threading Deep Dive」という記事において、Realmがオブジェクトグラフ全体を一貫して表示しつつ、ユーザーにロックやリソースの競合を解決するといった作業をさせないで済むように、いかにスレッドを取り扱っているかということを説明しました。特に、この設計は他のORMやデータフレームワークにおいては「フォールト」の概念を構築しています 💥。

公式ドキュメントのマルチスレッドセクションは、マルチスレッドでRealmを正しく使用する方法を真に理解するために必見の資料です。この資料に目を通すと、マルチスレッドとRealmを非常に生産的に使用できます。しかし、これまではオブジェクトはスレッド間で受け渡すことができませんでした。

Thread Confinement

Realmがスレッドセーフであるなら、なぜスレッドをまたいでオブジェクトを渡そうとすると例外が起こるのでしょうか!?

一貫性と安全性を保証するために、シンプルな制約を課しているためです。Realmインスタンス、オブジェクト、Resultsオブジェクト、およびListオブジェクトは、それが生成されたスレッド内でだけ利用することができる、という制約です。

「Thread Confinement」という制約は、Realmの内部構造や人為的な制約に基づく一時的な制限ではなく、正確なコードの記述を容易にする設計の重要な部分であることを理解することが重要です。

実際に、Realmオブジェクトをスレッド間で自由に受け渡せるようにすることを実装するのは非常に簡単ですが、正しく使用するのが非常に危険で難しく、予測不可能になるというトレードオフがあります。

Realmは、トランザクションベースのデータベースであり、データが中途半端な状態でディスクに永続化されることはありません(書き込みトランザクションの範囲でデータの整合性を保証できます。)。

独立性(ACIDの「I」)を保証するために、別のトランザクションの変更は、トランザクションがコミットされるまで他のトランザクションからは見ることができません。そうでなければ、Realmはこの設計によって「フォールト」を読み込んでしまうでしょう。

この独立性を保証するために、特定のスレッドのRealmは同じ時点のデータを保持しています。(実際にはスレッドごとに1つのRealmしかありません)。 Realmやオブジェクト、クエリなどをスレッド間で自由に受け渡せてしまうと、異なる時点のデータを混在させることになり、非常に難しい結果につながります。 たとえば、オブジェクトを削除した後のスレッドにオブジェクトを渡すとクラッシュする可能性があります。また、スレッドをまたいで値が変更される可能性があります。別のトランザクションで異なる関連を持つこともできてしまいます。

データをスレッド間で受け渡すこれまでの(古い)やり方

これまでは、データをスレッド間で受け渡す際には、Realmが管理していないオブジェクトを渡さなければなりませんでした。

それはつまり、アンマネージド(Realmに永続化されていない)のオブジェクトを渡すことだったり、プライマリーキーを渡して、読み込み直すといったことだったりしました。

let realm = try! Realm()
let person = Person(name: "Jane", primaryKey: 123)
let pk = person.primaryKey
try! realm.write {
  realm.add(person)
}
DispatchQueue(label: "com.example.myApp.bg").async {
  let realm = try! Realm()
  guard let person = realm.object(ofType: Person.self,
                                  forPrimaryKey: pk) else {
    return // person was deleted
  }
  try! realm.write {
    person.name = "Jane Doe"
  }
}

しかし、オブジェクトがプライマリキーを持っていなかったら、この方法はうまくいきません。また、古いデータを使ってしまう可能性があります。ListResultsLinkingObjectsのようなRealmオブジェクト以外のものを渡すことも、このアプローチでは簡単に行えません。

スレッドセーフ参照を使用する

これからは、以前に「Thread Confinement」とされていたオブジェクトすべてに対して、スレッドセーフ参照を利用することができます。そしてよりシンプルに、次のような3ステップだけでスレッド間で受け渡すことができます。

  1. ThreadSafeReferenceを「Thread Confinement」なオブジェクトを用いて生成する。
  2. ThreadSafeReferenceを別のスレッドに渡す。
  3. 渡された参照を保存されているRealmインスタンスのRealm.resolve(_:)メソッドの引数に渡し、参照を解決する。このメソッドの戻り値として取得したオブジェクトは通常のオブジェクトと同じように使えます。

例:

let realm = try! Realm()
let person = Person(name: "Jane") // no primary key required
try! realm.write {
  realm.add(person)
}
let personRef = ThreadSafeReference(to: person)
DispatchQueue(label: "com.example.myApp.bg").async {
  let realm = try! Realm()
  guard let person = realm.resolve(personRef) else {
    return // person was deleted
  }
  try! realm.write {
    person.name = "Jane Doe"
  }
}

現実的な例 🌏

オープンソースとして公開されているRealmTasksアプリをご覧ください。iOS PR #374というプルリクエストによって、古いやり方でオブジェクトをスレッド間で受け渡していた箇所が、スレッドセーフ参照を使う方法に書き換えられています。

下記は関連するコードの一部です。このコードは、バックグラウンドスレッドでListプロパティの重複を取り除く、という処理をしています。

realm.addNotificationBlock { _, realm in
  let items = realm.objects(TaskListList.self).first!.items
  guard items.count > 1 && !realm.isInWriteTransaction else { return }
  let itemsReference = ThreadSafeReference(to: items)
  DispatchQueue(label: "io.realm.RealmTasks.bg").async {
    let realm = try! Realm()
    guard let items = realm.resolve(itemsReference), items.count > 1 else {
      return
    }
    realm.beginWrite()
    let listReferenceIDs = NSCountedSet(array: items.map { $0.id })
    for id in listReferenceIDs where listReferenceIDs.count(for: id) > 1 {
      let id = id as! String
      let indexesToRemove = items.enumerated().flatMap { index, element in
        return element.id == id ? index : nil
      }
      indexesToRemove.dropFirst().reversed().forEach(items.remove(objectAtIndex:))
    }
    try! realm.commitWrite()
  }
}

関連のプロパティを用いて並べ替える

これまでは直接のプロパティを使うことでしか、Realmコレクションを並べ替えることはできませんでした。

Realm 2.2より、Realmコレクションを1対1の関連のプロパティによって並べ替えることができます。

例えば、PersonクラスのRealmコレクションを関連であるdogプロパティのageの値によって並べ替えるとします。その場合は、dogOwners.sorted(byKeyPath: "dog.age")のように書きます。

class Person: Object {
  dynamic var name = ""
  dynamic var dog: Dog?
}
class Dog: Object {
  dynamic var name = ""
  dynamic var age = 0
}

realm.beginWrite()

let lucy = realm.create(Dog.self, value: ["Lucy", 7])
let freyja = realm.create(Dog.self, value: ["Freyja", 6])
let ziggy = realm.create(Dog.self, value: ["Ziggy", 9])

let mark = realm.create(Person.self, value: ["Mark", freyja])
let diane = realm.create(Person.self, value: ["Diane", lucy])
let hannah = realm.create(Person.self, value: ["Hannah"])
let don = realm.create(Person.self, value: ["Don", ziggy])
let diane_sr = realm.create(Person.self, value: ["Diane Sr", ziggy])

let dogOwners = realm.objects(Person.self)
print(dogOwners.sorted(byKeyPath: "dog.age").map({ $0.name }))
// Prints: ["Mark", "Diane", "Don", "Diane Sr", "Hannah"]

以前のバージョンのRealmで、同様の動作を実現するには、Personオブジェクトにdog.ageと同じ内容のプロパティを格納するか、Resultsを使わずにRealmの機能を使わずにソートする必要がありました。その場合はResultsのメリットは失われてしまいます。

下記はAPIの変更点です。今回の改善により、「プロパティ」ではなくより正しい「キーパス」という用語を使用するように変更しました。

  • 下記のObjective-C APIは非推奨となります。新しいAPIを使用してください。
Deprecated API New API
-[RLMArray sortedResultsUsingProperty:] -[RLMArray sortedResultsUsingKeyPath:]
-[RLMCollection sortedResultsUsingProperty:] -[RLMCollection sortedResultsUsingKeyPath:]
-[RLMResults sortedResultsUsingProperty:] -[RLMResults sortedResultsUsingKeyPath:]
+[RLMSortDescriptor sortDescriptorWithProperty:​ascending] +[RLMSortDescriptor sortDescriptorWithKeyPath:​ascending:]
RLMSortDescriptor​.property RLMSortDescriptor​.keyPath
  • 下記のSwift APIは非推奨となります。新しいAPIを使用してください。
Deprecated API New API
LinkingObjects​.sorted(byProperty:​ascending:) LinkingObjects​.sorted(byKeyPath:​ascending:)
List.sorted(byProperty:​ascending:) List.sorted(byKeyPath:​ascending:)
RealmCollection.sorted(byProperty:​ascending:) RealmCollection.sorted(byKeyPath:​ascending:)
Results.sorted(byProperty:​ascending:) Results.sorted(byKeyPath:​ascending:)
SortDescriptor(property:​ascending:) SortDescriptor(keyPath:​ascending:)
SortDescriptor​.property SortDescriptor​.keyPath

Realmのバージョニングはセマンティックバージョニングに準拠しています。そのため、上記の非推奨となったメソッドはRealmがバージョン3.xになるまではそのまま残され、使用できます。

その他の変更

同期に関する非互換の変更(ベータ版のため)

  • 内部で使用している同期エンジンのバージョンをBETA-6.5にバージョンアップしました。
  • 同期に関連するエラー通知の挙動が変更されました。特定のユーザーまたはセッションに関連しないエラーは、同期エンジンによって「致命的」と分類された場合にのみ通知されます。

不具合の修正

  • deleteRealmIfMigrationNeededを設定すると、Realm 0.xで作られたファイルを1.x、または1.xのファイルを2.xで開く場合など、ファイルフォーマットの移行が必要な場合にもRealmファイルが削除されるようになりました。
  • ネストされたサブクエリを含むクエリを解釈できない問題を修正しました。
  • 古いスレッドからのRLMRealmインスタンスがまだ存在している間に、スレッドIDが再使用されたときに誤った例外が発生する問題を修正しました。

古いSwiftバージョンのサポートについて

Xcode 7.3.1とSwift 2.2のサポートはできる限り長い間続ける予定ですが、できるだけ早くXcode 8に移行することをおすすめします。


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

Read more

Realm ObjC & Swift 2.3: 同期の進捗を通知、共有機能の改善、バックアップと復元!

by /

Realm Objective‑CおよびRealm Swift 2.3をリリースしました。 このバージョンには同期の進捗の通知、バックアップと復元、より柔軟な共有の仕組みなどRealm Mobile Platformに関する改善が含まれます。詳しくは下記をご覧ください。

同期の進捗の通知

Realm Mobile Platformは完全なオフラインファーストのユーザー体験を提供します。ネットワークの状態に関係なく、ローカルのRealmには即座に変更をいつでも加えることができます。その背景には自動的な同期が常に実行されており、ネットワーク通信が可能になるとすぐに、変更は即座に各デバイスとサーバー間で伝播します。このことにより、リアルタイムな共同作業が可能になります。このようなリアルタイムな共同編集を可能にするという機能が、Realmを差別化する大きな特長です

しかし、データが今どのくらい転送されたのかを知りたいときもあります。それは例えばアプリを最初に起動するときがそうです。画面を表示する前に、サーバーにあるデータがこれからどれくらいダウンロードされるのか確認したいことでしょう。また、もっと単純にデータ同期中にプログレスバーやアクティビティインジケータを表示したいこともあるでしょう。

まさにそれが、今回のリリースで同期の進捗を監視できるAPIを追加した理由です。同期の進捗はSyncSessionに通知ブロックを追加することで行います。シンプルに、データがどっち向きに転送されるか(.uploadまたは.download)と、通知が継続するかワンショットで終わるのか(.reportIndefinitely/.forCurrentlyOutstandingWork)をモードとして指定できます。

例えば、大きいサイズの画像をRealmに保存した際に、それがサーバーにアップロードされるまでのブログレスバーを表示したいときは、次のように書きます。

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

別の例として、Realmの通信中はアクティビティインジケータを必ず表示したいという場合は、次のように書きます。

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

新しい柔軟な共有の仕組み

リアルタイム共同編集とデータ同期はRealm Mobile Platformを支える重要な柱です。それを実現するためにモバイルデベロッパーに向けて、複数のユーザー間でRealmを共有する仕組みをPermissionChange APIとして11月に導入しました。

本日、より簡単に異なるユーザー間でRealmを共有する仕組みをご紹介します。とてつもなく柔軟な権限の管理を可能にし、サーバーサイドのコードは一切必要ありません。すべてはクライアント側のAPIだけでコントロールできます。具体的には、新しく追加したSyncPermissionOfferSyncPermissionOfferResponseクラスがを使って、権限の変更を要求したり、承認したりして、Realmの共有を実現します。

これらのAPIはRealm Mobile Platformが実現する「APIとしてのオブジェクト」というアプローチのデモンストレーションでもあります。権限の変更を要求したり受け取ることは、以前のPermissionChangeを利用したプロセスとほとんど同じ仕組みです。シンプルに各ユーザーのマネジメントRealmにオブジェクトを保存し、それがサーバーに同期されて処理された結果が返ってくることを通知を用いて監視します。

同期されたRealmを共有するには次のような手順で行いま

  1. SyncPermissionOfferオブジェクトを、ユーザーのマネジメントRealmに保存します。
  2. SyncPermissionOfferオブジェクトがサーバーによって処理されるのを待ちます。
  3. オブジェクトにtokenプロパティが割り当てられると、別のユーザーにトークンを送ります。トークンを送る方法はE-mailやiMessage、共有アクション、伝書鳩など、なんでも好きな方法で構いません!
  4. トークンを受け取ったユーザーはSyncPermissionOfferResponseオブジェクトを自分のマネジメントRealmに保存します。
  5. SyncPermissionOfferResponseオブジェクトがサーバーによって処理されるのを待ちます。
  6. SyncPermissionOfferResponseオブジェクトが処理されると、トークンを受け取ったユーザーは、共有されたRealmを開くことができるようになります。共有されたRealmのURLは、realmUrlプロパティで参照できます。

例:

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

Todoリストのデモアプリ、RealmTasksのProof-Of-Conceptブランチにて、この仕組みを用いて、どのようにRealmをユーザー間で共有するのかという原理のデモンストレーションを示しています。

バックアップと復元

もしサーバーがダウンしてしまったら、復元をしなければなりません。この数か月の間、Realm Mobile Platformにバックアップの機能を提供するために開発を続けていた理由です。本日、常に最新のバックアップを自動的に取得する、継続的なバックアップソリューションをご紹介いたします。

通常の状態では、Realmの同期エンジンは実際のデータではなく、操作手順だけを転送します。Realm Object Serverが新しい操作手順の受信を確認すると、ローカルログはクリアされます。これは、アプリのディスク使用量を小さくし、Realmが高速に動作するための仕組みです⚡️。

さらにいうと、Realmはオフラインファーストのデータベースであるので、Realm Object Serverが何らかの理由によりダウンしたとしても、ローカルデータは利用可能なままです。

しかしながら、バックアップからサーバーのデータを復元すると、クライアントはグローバルエラーハンドラーから”client reset”エラーを受信します。その状態でもローカルのRealmは通常と同じように使い続けることができますが、バックアップの後に記録された変更は失われてしまいます。

“client reset”エラーを受信した場合は、ユーザーに対してそのことを通知し、Realmへのアクセスを中止し、サーバーから最新のバックアップを取得しなおしてください。NSErrorオブジェクトのuserInfoプロパティはブロックオブジェクトを保持していて、それを呼ぶことで、ローカルの古いバージョンのRealmをクリアできます。

もし、”client reset”エラーをすぐに処理しない場合は、次回以降の起動時にRealmにアクセスすると、ローカルの古いRealmは削除され、サーバーから最新のバックアップが自動的に再ダウンロードされます。

不具合の修正

  • commitWrite(withoutNotifying:)に関して、トランザクションをコミットした際に、次回以降の通知が間違ってスキップされてしまう問題を修正しました。
  • 同期によってコンフリクトしたオブジェクトをマージした際に不正な結果を生み出し、コレクション通知でクラッシュを引き起こす問題を修正しました。

古いSwiftバージョンのサポートについて

Xcode 7.3.1とSwift 2.2のサポートはできる限り長い間続ける予定ですが、できるだけ早くXcode 8に移行することをおすすめします。


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

Read more

リアルタイムな同期とスケーラビリティ: Realm Mobile Platform 1.0

by /

本日、Realm Mobile Platform 1.0をリリースし、小規模なアプリから大規模なサービスまで、安定して商用でお使いいただけるようになりました。この数か月間、私たちは機能追加だけでなく、不具合の修正や、細部の改善に至るまで、努力を続けてきました。ついに1.0のバージョンに達したことは私たちにとって非常に大きな到達点だと考えています。そして現在Realmをお使いの方やコミュニティの方々に、これまで支えてくださったことを深く感謝します。ベータ版の間にいただいたフィードバックは本当に改善の手助けになりました。

Realm Mobile Platformはリアルタイムの共同編集や、チャット、安定したオフラインファーストのユーザー体験、など非常に複雑で難解とされている機能を持つアプリケーションの開発を容易にします。Realm Mobile Platformは非常に多くのシェアを持つiOSとアンドロイドのクライアントデータベースと、サーバーサイドの連携を担当するRealm Object Serverを統合します。そのことによって、自動的なリアルタイムのデータ同期を実現します。ネットワーク通信や、データ同期のコードは不要になります。Realmが代わりにデータ同期を提供します。デバイス上のデータは常にサーバーサイドのデータと同期するようになります。サーバーサイドの処理も簡単に書くことができます。サーバーサイドのデータ変更をトリガーにすることができるので、既存のシステムやAPIと連携することも簡単です。

今回のリリースより、Realm Mobile Platformのすべてのエディションにおいて、プロダクトの開発に利用できます。とても楽しいデモのコードを提供していますので、今すぐ試すことができます。お絵描きアプリのデモや無料のDeveloper EditionのMac版またはLinux版をダウンロードしてすぐに試すことができます。

3つの新機能

このリリースにはEnterprise Editionにおいて、3つの新機能が含まれています。

Data Integration API

新しいData Integration APIを使うと、Realm Mobile Platformとあらゆるデータソースが容易に連携できるようになります。既存のサービスやデータベースに接続し、リアルタイムな機能を持つアプリケーションを簡単に作ることができます。ベータ版をお使いのほとんどの方が、この新機能をレガシーシステムを「モバイル化」しようとする際に、この新機能を強力に活用されています。Realmをリアルタイム機能のブリッジとして利用することで、既存の古いシステムに接続するAndroid、iOSアプリをモダンに、リアクティブに作り変えることが容易に可能になります。=

例えば、リテール事業者がまったく新しいショッピング体験のサービスをリリースしようとしています。しかし、その新しいアプリは、既存の決済システムをこれまでと同様に利用する必要があります。このとき、Realmの新しいData Integration APIを用いて、Realm Object Serverを既存のデータベースに接続し、Realm Object Serverと決済システムのデータベースを同期して同じデータが参照できるようにします。どこからアクセスしても同じデータが保証されるように、不安定な接続を排除し、中断してしまったトランザクションは自動的に再実行するように設計されています。この保証があるので、Realm Object Serverはクライアントサイドのデータベースと決済システムのデータベースのミドルウェアとして動作することになります。これまでのシステムやデータベースの資産をRealmを用いた新しいシステムに効果的に活かすことができるのです。

Data Integration APIでは独自のコネクターをカスタムすることも容易です。標準で用意されているコネクターとしてPostgreSQLに接続するコネクターがあります。Oracle、MongoDB、Hadoop、SAP HANA、Redisといった他のデータベースに接続するコネクターも現在開発中です。まもなく標準の組み込みコネクターとして利用できるようになります。

水平スケーラビリティ

Realm Mobile Platformは動作しているハードウェアの制約の中において、非常に堅牢に安定して動作します。単体のRealm Object Serverは10,000ユーザー以上の同時接続数を扱えます。さらにサービスの急成長に備えて、水平スケーリングをEnterprise Editionに追加しました。自動的にコネクションを分散させるロードバランサーも含まれます。このことにより、複数のRealm Object Serverインスタンスを並列化して動作させることができます。100万ユーザー以上の同時接続数を扱うサービスであっても問題ありません。

継続的バックアップ

継続的バックアップはRealm Object Serverのデータをセカンダリサーバーに自動的にバックアップします。停電やハードウェアの故障、自然災害といった障害の発生時においても、セカンダリサーバーを用いてサービスを継続することができます。セカンダリサーバーをどこに配置するかは自由に選ぶことができます。ディザスタリカバリ耐性を高めるために異なるリージョンを選ぶこともできます。

Enterprise Editionの新機能

Realmを使うための準備、お絵描きデモアプリ

Realm Mobile Platformを使うための最初のステップは、ローカルマシンかクラウドサービスを利用するかを選ぶことです。イベントハンドリングなどのPro Editionの機能に特に関心がない限りは、Developer Editionをまず使ってみることをお勧めします。強力な機能を無料で利用できます。利用期限もありません。商用のアプリやサービスにも自由に使うことができます(詳しくはライセンス規約をご覧ください)。インストール方法の詳細や実行の仕方についてはドキュメントに記載しています。

Realmをインストールしたなら、もうサンプルコードを動かす準備は整っています。お絵描きアプリはホワイトボードを共同編集できるアプリです。複数のユーザー間でリアルタイムなデータ同期をRealmで扱うという機能をご覧いただけます。このデモは完全にオープンソースとしてGitHubにて他のデモとともに公開されています。次のビデオは2台のiPad間でリアルタイムにデータが同期される様子を収めています。またネットワーク通信が一時的に圏外になっても自動的に復帰するところに注目してください。

さらに詳しく知るには

さらに詳しくRealm Mobile Platformついて興味があったり、質問をしたい時には、プロダクトチームによるライブ講義を1月31日の深夜に開催します。ぜひこちらから登録してご視聴ください。

Read more

リアルタイムの共同編集をすべてのモバイルデベロッパーに

by /

Realm Mobile Platformをリリースしてから、複数のユーザー間でデータを共有し、リアルタイムな真の共同作業機能を追加すると、アプリケーションがどれだけ強力になるかがわかりました。これを実現するために必要な主要要素は、クライアントが変更できるアクセスコントロールであり、その機能を利用できるのは、有料のエンタープライズ版だけに限られていました。現在では、Realm Mobile Platformのすべてのエディションにアクセスコントロールを導入しているため、すべてのモバイルデベロッパーは、無料のDeveloper Editionを使用していても、複数ユーザー間のリアルタイムな共同編集をアプリで使用することができます。

これを実現するために、CocoaおよびAndroidクライアントSDKに新しい機能を追加し、Realm Object Serverによって管理されていたRealmに対するアクセスコントロールのAPIを公開します。これにより、データにアクセスできるユーザーを制御できます。

仕組みは簡単です。あるRealmを作成したユーザは、PermissionChangeオブジェクトを作成し、ユーザと新しい権限(mayReadmayWriteなど)を指定することで、他のユーザーとRealmを共有できます。PermissionChangeオブジェクトが作成された後、そのオブジェクトは特別なマネジメントRealmに保存され、Realm Object Serverに同期され、変更が指定したユーザーに適用されます。

![Client Permission diagram](// images.contentful.com/emmiduwd41v7/6qKfHOgawo0uw84SI8OmKS/b7be3a1bcfff38be8943f589a58198b1/Screen_Shot_2016-11-29_at_9.18.29_AM.png)

</ div>

PermissionChangeオブジェクトを専用の同期されたRealmに保存することで、Realm Object Serverと通信しています。Realm Mobile Platformが提供する「APIとしてのオブジェクト」というアプローチをとても自然に利用しています。PermissionChangeオブジェクトは自動的に同期され、Realm Object Serverは変更を監視し、オブジェクトのステータスを更新します。つまりオブジェクトはAPIとなり、オフラインファーストで、ネットワーク障害を気にする必要がありません。クライアント側で少しコードを書くだけなのです。

新しいAPIの使用方法については、[Realm Object Serverについてのドキュメント](https://realm.io/docs/realm-object-server/#access-control)とCocoaおよびAndroidの関連セクションを参照してください。 そして、無料のDev Editionをダウンロードしてください。クールなアプリやサービスを開発したらぜひ知らせてください。Realmを使ったアプリを楽しみにしています。

Read more

Realm Mobile Platformのご紹介

by /

 

イントロダクション (0:00)

Realmについて関心があった方々には、Realm Mobile Platformがやってくるのは分かっていたかもしれません。少なくとも2年以上の歳月をかけたプロジェクトでしたので、調査の段階からかなり大変でした。

Realmの目標は、開発者がより優れたアプリを簡単に開発できるようにすることでした。驚くようなライブ体験やインタラクティブな機能を備えていて、迅速かつ簡単に構築できるものです。今このようなものを作るのは苦労します。

Realm Mobile Database (0:58)

Realmにはとても長い歴史があり、今ではすばらしいことを成果をあげています。オフィスはサンフランシスコやコペンハーゲンにあります(Realmはデンマークから始まりました)。社員は50名ほどいて、投資を受けている段階です。しかし、最初はこうではありませんでした。デンマークにいながらモバイルデータベースを作るというクレイジーなアイデアを持っていた私と共同創業者だけではじまったのは面白いでしょう。

まずY Combinatorに応募しました。Y Combinatorに応募すれば、みんな我々のことを知っているし、プロフィールにマッチした人がいるなどと言うのですが、私たちは二人ともずっとデンマークで一人で座っているような人でした。誰にも知られていなかったし、自分たちのスキルと、ノキアで長く携帯の仕事をしていたということ以外に資格はありませんでした。私たちは全く無名で、とても素朴でした。

それでも、アプリのビデオを送ると、受け取ってもらえたことには驚きました!これは長い話になりますが、たくさん努力して、あらゆるものを稼働させました。モバイルデータベースを作り始めたのです。私たちがやりたいことの核となるエンジンでした。

若い頃、「どれぐらいの時間がかかるだろうか」と考え始めました。この分野で多くの経験を積んでいたので、売れるようになるまでには半年ほどかかると見積もりました。そして数年後、実際、まともな製品になっています!2014年に会社を設立してからおよそ3年後にローンチしました。組み込みデータベースを構築するのには長い時間がかかります(特に、それが良いものの場合)。私たちが始めたときにはわからなかったことは、今思えばおそらく良いことです。なぜなら、何も始まっていないかもしれないからです。そして今はここにいます。最高です!

今は、この技術を適切に整え、開発し、すべてオープンソース化しました。これはとてもすごいことです。始めたときからオープンソース化することを約束していました。そして今、みなさんにRealmで何でもしたいことをしていただけます。世界に物を与えるのはいつでも楽しいです。

私が最も満足しているのは、こんなにたくさんの人がRealmを愛してくれていることです。 Realmがいかにクールかということを語っていただいているツイートやフィードバックがたくさんあります。Realmはまた、いたるところで使われています。素晴らしいです。たくさんのアプリを変えてきたと自負しています!

Realm Mobile Platform (5:04)

Realm Mobile Databaseをリリースしてから、次の段階に進む必要がありました。クールなデータベースを作って無料で提供するのはすばらしいことなのですが、それでは持続する会社を作ることにはなりません。Realm Mobile Platformが必要だったのです。

みなさん知らないと思いますが、私の会社でテキストエディタを作っており、Realmの元々のインスピレーションはあったのです。(Gitが作られる前の)Gitを組み込んだコラボレーションテキストエディタでした。リアルタイムコラボレーションをしたいと思っていました。私が探していたタイプのリアルタイムコラボレーションを行うのに十分な速さのデータベースはなかったので、自分のために作りたかったのです。それを作り始めましたが、全体の構想としては、人々がリアルタイムにデータを共有できる理想的なデータベースを構築することでした。実際にデータベースを作る必要があるため、時間がかかります。

同期に対してはたくさんのリクエストがありました。たくさんの人たちが、いつやって来るのかを知りたがっていました。今、リアルタイムで動作して、アップデートができて、リアクティブなものがほしいと思っているでしょう。今はアプリでリアルタイムに動くものを作るのは難しいです。UIにデータを接続するだけで、更新しなければなりません。Realm Mobile Platformでは、ほぼすべてのコードでこれらの機能を使うことができます。これは簡単です。

すべてのオブジェクトを作成してUIに接続するだけで、動作するためのリアクティブなセットアップが必要です。私の元のビジョンでは、それは連携できるものでなければなりません。誰もが携帯電話を持っているので、みなさんは連動することを望んでいます。すべてのアプリは連携している必要があります。猫の写真を共有するだけではなく、作るのに役立つはずです。ユーザーがすることを助けられる高品質のアプリを作る必要があります。誰もがオンラインでもオフラインでも機能するシームレスな体験をしたいと考えています。これがビジョンであり、ユーザーから聞いた声です。

Realm Mobile Platformは、データベースと同じものです。デバイス上に実際のデータベースを持っている場合にのみオフラインで行うことができます。これは重要なことです。それ以外の場合は、いつも失敗し、UXはよくありません。この魔法はあなたがデータベースを持つことができるということですが、データベースは単なるウェブページです。ディスク上のファイルパスを使ってデータベースを開くのではなく、URLを使ってファイルを開くだけです。Shared Realmを開き、それを1つ、10個、または数百個開くことができます。同じURLを開く人は、同時に同じデータをリアルタイムで持ちます。非常にシンプルなコンセプトですが、実際に作業するときはとても驚きます。

この構想は、データベースがオフラインであることです。実際のオブジェクトデータベースだからです。これは、OM層を持つSQLデータベースではなく、矛盾したデータで前後にデータをコピーします。リレーショナルデータベースなので、すべてのものにリンクすることができます。反応のあることを可能にするチェーン通知もあります。これで、ネットワーク処理を完全に抽象化できます。通信について考えるのではなく、URLでRealmを開くだけで、同じRealmを開いた人と勝手に同期します。

他のクールなものとしては、データベースとネットワークの両方で、今日あなたが間違いなく望んでいる暗号化が含まれます。これはリアルタイム同期を行い、実際にはイベント処理が行われるため、サーバー上でコードを実行し、応答の変化を見ることができます。

もちろん、実際の魔法は自動コンフリクト解決にあります。あなたが変更を調整できるという事実です。手動ではなく、自動コンフリクト解決を使うするのはなぜでしょう?問題は、手作業によるコンフリクトの解消を行うと、物事が止まるだけで実際にリアルタイムに行うことができないということです。本当にリアルタイムでそれが行なわれるようにしたいので、自動でなければなりません。

実際にスキーマを変えることができます。データをデバイスにプッシュでき、イベントフレームで既存のインフラに導入できます。すべてのデバイスがサーバーに接続しています。サーバーには、すべての自動コンフリクト解決が機能する同期エンジンがあります。これは、サーバー上でコードを実行するイベントフレームワークを持っています。もちろんダッシュボードがあるので、何が起きているのかを見ることができます。認証とアクセス制御があり、すべてのRealmがあります。すべてのデバイスにはそれぞれ固有のRealmがあり、Realmはすべてのデバイスで共有されます。欲しい数だけRealmを持つことができます!これにより、スケールアップできるようになり、数百万のRealmを持つことができます。基本的には、それらの周りにデータを広げることになります。他のサーバーにも接続できるため、バックエンドのデータベースやAPIを使用している場合は、実際にそれらのコネクタに接続することができます。既存のインフラに統合されます。

ライブオブジェクト (11:09)

これを可能にする重要なことは、すべてオブジェクトの下にあるという考え方です。それはオブジェクトであり、オブジェクトはライブです。すでにRealmを使用している場合は、複数のスレッドを使用していても、複数のスレッドを変更することはできますが、それでも安全であれば、他のスレッドに更新が表示されます。私たちはさらに一歩踏み出し、それはネットワークでも起こると言っておきます。複数のデバイスを持つことができ、すべてオブジェクトを更新しますが、いつも同じことです。ただのオブジェクトであり、変化します。オブジェクトはデータモデルであり、実際にメンタルモデルを単純化します。これは、アプリを構築し、維持することをとても簡単にします。この考えは、通常はそれを行うのと同じ構文でオブジェクトを正確に定義できるということです。

これらのオブジェクトは通常のオブジェクトのように作成しますが、突然それをスーパーチャージするようなものです。トランザクションとクエリを実行し、永続性を持たせることができ、すべてのトランザクションを自由に取得できます。それだけでうまくいきます。さらに、まだデータベースとしていっぱいですが、それはObservableです。これらの機能を使用すると、アプリで必要なものを作成することができます。

Realm Mobile Platformはすぐに利用できるので、今すぐダウンロードしましょう!開発者向けには完全無料版があります。自分のハードウェア上で実行し、必要なものを構築することができます。

また、エンタープライズのニーズを解決し、バックエンドとの統合や、サーバー側の処理、カスタム認証が強化された商用版(会社で使ってる方必見!)があります。しかし、無料版でも超強力です!レート制限なしでアプリを完全に構築することができます。あなたがしたいことは何でも、いつでも使うことができます。

Read more

Realm Professional Editionのリリース: モバイルアプリにおけるリアクティブプラットフォーム

by /

Realmのミッションは、デベロッパーのみなさまがより良いアプリを迅速に開発できるようにすることです。デベロッパーがRealmのライブオブジェクトを用いて簡単にモバイルアプリを開発できるようになり、リアルタイムで自動的にデータが同期され、データの変更に応じて簡単にサーバーサイドのロジックを動かすことができるといった、モバイルのインターネットに精巧に統合されたデータレイヤーの明確なビジョンを私たちは描いています。そのビジョンを現実のものにするために、Realm Mobile DatabaseとRealm Mobile Platformの機能を継続的に改善し続けてきました。

そのビジョンをさらに推し進め、より簡単にRealmをみなさまのアプリで利用できるようになる2つのお知らせがあります。一つ目は、本日、新しい価格設定でより利用しやすくなったRealm Mobile Platform Professional Editionをリリースします。もう一つは、IBMの協力によって実現したScannerというProfessional Editionのためのデモアプリケーションです。ScannerはIBM Watsonを用いて高度に洗練された画像解析を行います。画像解析と連携するリアクティブなモバイルアプリのテンプレートしても利用できるよう、オープンソースで提供されます。

RMP Professional Edition

Professional Editionは中規模の企業向けにデザインされた新しいライセンス形態です。Professional Editionではリアルタイムの自動データ同期などのDeveloper Editionで利用できるすべての機能に加え、イベントハンドリングやサーバーサイドのデータアクセスといったEnterprise Editionに含まれる機能も利用できます(詳しくは後述します)。Professional Editionは同期の機能やリアルタイム性は欲しいけれども、Enterprise Editionに求められるような大規模なスケーラビリティは必要ない、といった方に最適です。Professional Editionは本日よりダウンロードできます。60日間は無料で試用できます。

Professional Editionのリリースは、Realmの機能をダウンストリームに継続的に移行し、新しい価格設定とパッケージングにより、さらに多くのデベロッパーの方々に利用していただけるという、非常に長期にわたって続くパターンを確立します。 RMPには3つのバージョンがあります。Developer Editionは、完全に無料で誰でも利用できます。プロフェッショナル版は、中規模の企業を対象とし、月間1500ドルから利用可能です。数万人の同時接続ユーザーを処理できます。Enterprise Editionは、最大のユーザー数を扱うことができ、ユースケースの規模に基づいて価格設定されます。すべての機能が利用できます。私たちは、みなさまのニーズを理解するために緊密に連携していますので、各エディションと価格についてご質問があれば、こちらまでご連絡ください。

Scannerの紹介: IBMとRealmのコラボレーション

Professional Editionの初期バージョンをIBMに公開すると、すぐに非常にクリエイティブなアプリを作ってくれました。それがScannerです。Scannerは画像分類、顔検出、テキスト認識などの洗練されたサーバーサイドの画像解析を用いて、ユーザーが撮影したものは何でも解析することができるRealmのデモアプリケーションです。ScannerはIBM WatsonのVisual Recognition APIに加え、Professional Editionの重要な機能であるリアルタイムデータ同期とイベントハンドリングを利用しています。さまざまなリアルタイム性を必要とするアプリでこのようなコードが利用できるであろうことを想像してみてください。VRアプリにおける位置検出、セキュリティ分野の顔認識システム、科学研究における画像分類、小売業で用いられるラベルの自動認識などです。これからは想像するだけではなく、実際にプログラミングすることができるようになります。Scannerアプリのコード(SwiftとAndroid)はオープンソースプロジェクトとして公開されています。先にチュートリアルを読むのもいいでしょう。IBMチームからは私たちとのコラボレーションについてのブログエントリが公開されていて、そこにはデモアプリの動画も含まれています。

Scannerが採用しているアーキテクチャはRealm Mobile Platformを使う上で非常によく使われるパターンです。これをAPI mobilizationと名付けました(一般的には「API bridging」とも言われています)。反応が良く、優れたUXが求められるモバイルアプリで必要とされますが、そのようなアプリはしばしば同時に既存のAPIと連携することも求められます。既存のAPIはIBM WatsonのようなモダンなAPIの場合も、古いレガシーシステムと連携しなければならない場合もあります。モバイルデベロッパーにとって、もっとも困難なことは、すべてのネットワークアクセスは非同期で行われ、通信はいつでも失敗する恐れがあることです。複雑なビジネスロジックを処理するために、決まった順序でAPIアクセスを行わなければならないプロジェクトをたくさん知っています。ネットワークアクセスを管理し、非常の多くの異常ケースに対応するために、膨大なコードが必要になります。その上、APIから取得したデータをJSONのような別の形式に変換する際には、シリアライゼーション/デシリアライゼーションが必要で、データ構造が変わった際には新たな不具合を発生させてしまう恐れがあります。

API mobilizationはRealm Platformをミドルウェアとして利用します。モバイルアプリケーションはRealm DatabaseをiOSやAndroidといったクライアントサイドから利用します。Realm Platformによってデータは自動的にサーバーサイドに同期されます。サーバーサイドではRealm Platformのイベントハンドリングを利用して、クライアントサイドからデータが変更されたことを検知します(例: 新しい画像がアップロードされた)。データをWatsonによって処理し、結果をサーバーサイドのRealmに保存すると、それは自動的にクライアントサイドにも反映されます。このようにすることで、ネットワークアクセスや、データ変換のコードをアプリケーションから取り除くことができます。Realm Platformはデータ転送における複雑な処理をすべて肩代わりするので、デベロッパーのみなさまは、使い慣れたプログラミング言語でローカルのRealm Databaseを操作するだけで済むようになります。

使ってみてください

デベロッパーのみなさまがRealmを使ってアプリを開発してくれることを楽しみにしています。無料トライアルのProfessional Editionをダウンロードして使ってみてください。Scannerアプリを動かしてみたり、自分のアプリに組み込んでください。フィードバックや感想はこちらまでお知らせください。

Read more

Realm2016まとめ

by /

Realm Advent Calendar 2016 1日目の記事です。

2014年にObjective-C向けのモバイルデータベースとしてスタートしたRealmは、3年目となる2016年に、対応プラットフォームと機能の両面において大きく進化しました。

そこで、2016年のRealm関連重大トピックと、Realm製品群についてまとめてみました。


トピック

まずはじめに、2016年に起こったRealm関連のトピックのうち大きなものを見ていきます。

Realm 1.0

はじめに挙げられる大きなトピックといえば、Realm Java、Realm Objective-C、Realm Swiftがそろって1.0を迎えたということでしょう。

それまではバージョン1未満のベータ版という扱いでリリースを重ねつつフィードバックを元に互換性のない変更も取り入れてきましたが、APIも安定してきたと判断され1.0を迎えることになりました。

バージョン1.0以降、セマンティックバージョニングのルールに従いバージョン番号が更新されています。

この時点でRealm React NativeやRealm Xamarinも公開されていましたが、公開からまだ間もないということもあり1.0とするのは見送られました。

プラットフォームの拡大

2016年はRealmにとってプラットフォーム拡大の年でもありました。今年リリースされた新プラットフォームには以下のものがあります。

これらのリリースにより、広範囲なモバイルプラットフォームとNode.jsによるサーバーサイドの対応がなされました。

Realm Mobile Platform

9月27日、マルチプラットフォームを含む複数デバイス間でのデータ同期ソリューションを提供するRealm Mobile Platformをリリースしました。

このリリースに合わせ、それまで単にRealmと呼ばれていた各モバイルプラットフォーム上でのデータベースプロダクトが新たにRealm Mobile Databaseと呼ばれるように変更されています。

Realm Mobile Platformは、サーバーサイドで動くRealm Object Serverをハブとして、複数のRealm Mobile Databaseが保持するデータを同期する構成になっています。

The Realm Mobile Platform

現時点でRealm Mobile Platformに対応するRealm Mobile DatabaseはJava、Swift、Objective-C版のみですが、その他のプラットフォームについても順次対応していく予定です。

詳細については、リリースのお知らせや、公式ドキュメンテーションを御覧ください。

Coreのオープンソース化

Realm Mobile Platformの公開に合わせてRealm Coreがオープンソース化されました

リポジトリはこちらです。

Realm CoreはすべてのRealm Mobile Databaseで利用されているデータベースエンジンで、C++で記述されています。CoreはRealmの高速性を実現するための大切な要素です。

Realm Mobile Database

次に、各プラットフォーム上で動作するデータベース製品であるRealm Mobile Databaseについて、見ていきます。

Swift/Objective-C

Objective-C版とSwift版は、基本的に同じ機能を提供するためまとめて紹介します。

公���ドキュメンテーションはSwift版はこちらObjective-C版はこちらです。

ソースコードのリポジトリはこちらです。

最も歴史の長いプロダクトであり、Realm Mobile Platformへの対応、Realm Mobile Databaseの機能両面において一番多くの機能を提供しています。

iOS上での動作に加え、OS X上での実行もサポートしています。

Java(Android)

Java版と呼ばれていますが、現時点ではAndroidのみに対応しています。

公式ドキュメンテーションはこちらです。

ソースコードのリポジトリはこちらです。

ほぼフル機能をサポートしていますが、Swift版に比べると以下の機能が未提供です。

  • 粒度の細かい変更通知
  • 変更通知スキップ
  • マルチプロセスでの単一ファイル利用
  • managedなRealmCollectionによる動的なinクエリのサポート

これらについても順次提供していく予定です。

また、通知機構はLooperベースのスレッドでのみ利用可能という制限事項も存在します。

他のプラットフォームにない特徴としては、 Realm Mobile Platform対応がオプトインであるという点が挙げられます。Androidアプリケーションはメソッド数が64k個を超えると特別な対応が必要になります。そのため、Realm Object Serverでのデータ同期が不要なアプリについてはローカルで必要なAPIに絞ってアプリケーションに取り込むことができるようになっています。

Xamarin

公式ドキュメンテーションはこちらです。

ソースコードのリポジトリはこちらです。

12月1日時点の最新版は0.80.0です。

開発環境としてWindows上ではVisual Studioを、OS X上ではXamarin Studioをサポートします。

また、動作プラットフォームとしてiOSとAndroidをサポートしています。

0.80.0では、Swift版と比べると以下の機能が提供されていません。

  • プライマリキーによる更新
  • モデルに対するフィールドの初期値指定
  • 非同期クエリ
  • 粒度の細かい変更通知
  • 変更通知スキップ
  • Realm Mobile Platform対応

1.0に向けて、これらの機能の実装を進めています。

React Native

公式ドキュメンテーションはこちらです。

ソースコードのリポジトリはこちらです。

12月1日時点の最新版は0.15.0で、プラットフォームとしてiOSとAndroidをサポートしています。

0.15.0では、Swift版と比べると以下の機能が提供されていません。

  • モデルに対するフィールドの初期値指定
  • 非同期クエリ
  • 粒度の細かい変更通知
  • 変更通知スキップ
  • Realm Mobile Platform対応

1.0に向けて、これらの機能の実装を進めています。

Node.js

リリース後まもないため、12月1日現在ではまだ公式ドキュメンテーションは提供されていません。唯一公開されている情報はリリースのブログエントリです。

ソースコードのリポジトリはReact Native版と共通でこちらです。

Node.js版はnpmを通じて提供されます。APIやについてはほぼReact Native版と同じと考えていただいて問題ありません。

Node.js版については、順次情報提供を進めていきます。

最後に

2016年はRealmにとって大きなイベントが盛りだくさんの年でした。来年は今年以上に盛りだくさんな年にしていきたいと思っています。

ぜひRealmプロダクトを使って素晴らしいモバイルアプリケーションを作っていただければと思います。

Read more

Nodeにおける初のオブジェクトデータベース: Realm Node.js

by /

RealmではこれまでモバイルデベロッパーにフォーカスしてRealm Mobile DatabaseをSwift、Objective-C、Java、XamarinとReact Nativeに対して開発し、オープンソースとして提供してきました。本日、完全に新しい挑戦としてRealm Node.jsをリリースします。Nodeにおける初の真のオブジェクトデータベースです。本日から無料で完全にオープンソースとしてリポジトリが公開され、NPMを用いて npm install --save realm を実行するだけで利用できます。

これまで何年もの間、モバイルデベロッパーのみなさまから、サーバーサイドで動作するRealmが欲しいという本当にたくさんのご要望をいただいていました。長い間タスクリストに残ったままで、優先度は高くありませんでした。しかし、その状況はRealm Mobile Platformを9月にリリースしたことにより変わりました。何人ものお客さまから、Node APIについてお問い合わせをいただきました。私たちは、非常に迅速に(およそ2、3日)Nodeにおけるプラットフォーム戦略を策定し、Realm Node.jsを完成させました。

どういうもので、誰のためのものですか?

Realmはオブジェクトデータベースです。そのため、以前からオブジェクト指向でオブジェクトを扱っていたのと同様に、簡単にオブジェクトとしてデータを扱うことができます。異なるのは、オブジェクトがディスクに簡単に、かつ効率的に永続化されるということです。JSONにシリアライズする必要はなく、テーブルに表示するためにORMを使う必要もありません。ただオブジェクト指向開発における原則を守っているだけでいいのです。そしてすべてのモバイルクライアントサイドのプラットフォーム上で動作します。さらにこれからは、サーバーサイドのNode.js上でも動作します。

モバイルデベロッパーの方々にとっては、Realm Node.jsを用いて、事前にデータを入力しておいたRealmをマスターデータとしてクライアントに送信できます。これは、面倒なアプリサイズ制限を回避することができるなど、非常に便利です。これはモバイルデベロッパーのみなさまが何年も昔から求めていることです。

しかし、初期バージョンをバックエンドデベロッパーの方に見せたところ、当初考えていたよりもNodeコミュニティにとってもっと広く役立つかもしれないとわかったので、より興味深くなってきました。例えば、複数のNodeインスタンス間でライブデータを共有できると便利です。このことを説明するために、1つのマシン上で2つのNodeプロセスを動かしながら、Realmを用いるとシリアライズも、デシリアライズも必要なく、データが共有できるというデモを作成しました。

Realmのユニークな機能の1つはリアクティブアーキテクチャです。Realmはマルチバージョン同時実行制御を使用して、スレッドとプロセス間におけるデータベースへの並列アクセスを提供します。このことにより、読み取りは決して書き込みをブロックせず、一貫したデータベースのビューを保持することでACID準拠を保証します。並行アクセスのためにRealmは通知の仕組みを使って、書き込みトランザクションが完了すると、アクセッサ(ビュー)を更新します。デベロッパーは、通知のAPIを利用して、データの変更をリアクティブに反映することができます。下記のサンプルコードでは、Node.jsデベロッパーがプロセス間通信にRealmの通知を利用して、2つの独立したサービス間でデータをやりとりする方法を示しています。

サンプルコードでは、2つの著名なNode.jsライブラリであるExpressをWebフレームワークに、ログ出力のライブラリにWinstonを使用しています。Expressを使ってHTTPエンドポイントを作成し、Winstonを使ってリクエストに関する情報を記録します。

var express = require('express'),
    util = require('util'),
    winston = require('winston');
    RealmWinston = require('./winston-realm').Realm;

var app = express();

// Use custom Winston transport: RealmWinston
// Writes log data to winston.realm
winston.add(RealmWinston, {});

app.get('/', function (req, res) {
  res.send('Hello World!');
  winston.info('Handled Hello World');
});

app.use(function (req, res, next) {
  res.status(404).send('Sorry can not find that!');
  winston.error('404 Error at: ' + req.url);
})

app.listen(3000, function () {
  console.log('Example app listening on port 3000!');
});

Realmのメリットを活用できるように、ログデータをRealmに保存するWinstonのカスタムプラグインを作成しました。ルートに対するアクセスでは“Hello World”をレスポンスとして返します。その他のパスに対するアクセスについては、404エラーを返し、対応するパスをエラーメッセージに記録します。Realmにログデータを保存することで、Realmの通知リスナーとして登録された別のNodeプロセスを開始し、変更に反応することができるようになります。

'use strict';

var Realm = require('realm');

let winstonRealm = new Realm({
  path: 'winston.realm'
});

// Register listener to print out log messages at error level
winstonRealm.objects('Log').filtered('level = "error"').addListener((logs, changes) => {
  changes.insertions.forEach((index) => {
    let log = logs[index];
    console.log(log.message);
  })
});

リスナーはRealmのコレクション通知を利用します。コレクション通知を用いると、追加・削除、または変更されたオブジェクトに対応するインデックスを知ることができます。サンプルコードでは、エラーレベルのすべてのログを取得するクエリにリスナーを追加し、ログメッセージをコンソールに出力しています。

サンプルコードは単純ですが、この機能は、マイクロサービスアーキテクチャ全体でデータをやりとりするような、より高度な応用も可能です。こちらの完全なデモをご覧ください。あなたのNode.jsプロジェクトでRealmを使い始めるなら、React NativeのドキュメントとAPIドキュメントをまずご覧ください。(コードベースはすべてのJavaScriptプラットフォームで共有されています)。

Realm Node.jsで他に特筆すべきことがありますか?ローカルメモリよりも大きなデータセットが利用できます。データに対しては通知やクエリが利用できます。複数のNodeインスタンスをまたがって、リアクティブなアーキテクチャを構築することができます。Dockerイメージ間でデータをやりとりすることもできるでしょう。ぜひ、いろいろな使い方を私たちに教えてください!

Read more

Realm Objective-C & Swift 2.1 – Collectionに対する通知を改善

by /

Realm Objective‑CおよびRealm Swift 2.1をリリースしました。 このバージョンにはコレクションに対する通知に関して、不具合の修正と改善が含まれます。詳しくは下記をご覧ください。

Background (on) Notifications

Realmはデータを常にリアクティブにオブジェクトそのものとして扱うアプローチをとっています。つい最近のRealm Mobile Platformのリリースにより、Realmを使って作られたアプリケーションは、別のスレッド、プロセス、はたまた他のデバイスなど世界中のどこで起こった変更に対しても、非常に簡単に反応することができるようになりました🌏!

コレクションに対する通知の更新情報は継続的に何が追加・削除・変更されたのかを表す操作として配信されます。ORMのように古い値と新しい値の差分を問題にしてるわけではないので、結果を引き起こした操作を正確に再現し、より美しいアニメーションを実現でき、それを簡単なコードで書くことができます。

これらの通知は常に非同期に配信されます。アプリのメインスレッドをブロックしたり妨害することはありません。ただし、変更をメインスレッドで同期的に実行し、即座にUIに反映する必要がある状況も存在します。このようなトランザクションを、インターフェース駆動型の書き込みと呼ぶことにします。

インターフェース駆動型の書き込み

UIスレッドで書き込みを行い、明示的にUIの状態に反映することを「インターフェース駆動型の書き込み」と呼びます。

たとえば、ユーザーがテーブルビューに項目を追加するとします。UIはユーザーがその操作を開始すると同時にアニメーションを伴って反映されるのが理想的です。

しかし、そのあとにデータ追加による通知が配信されてしまうと、すでにデータソースにはデータが追加されていて、UIにも反映されているにもかかわらず、通知により再び新しい行を追加しようとします。このように二重に追加しようとしてしまうことで、UIとデータソースの間に矛盾した状態を引き起こし、アプリをクラッシュさせてしまいます。💥NSInternalInconsistencyException💥

通知をスキップする書き込み

この問題を解決するために、通知の発生を抑制できる仕組みを用意しました。」

この仕組みを「通知をスキップする書き込み」と呼んでいます。

この機能は特に同期を有効にしたRealmと、コレクションに対する通知を使用している場合に有効です。「インターフェース駆動型の書き込み」についての回避策はアプリが完全に状態をコントロールできることを前提にしているので、同期が有効なRealmでは、変更が同期されるたびに通知が発生するためタイミングを完全にコントロールできないからです。

コード例

// Add fine-grained notification block
self.notificationToken = self.collection.addNotificationBlock { [unowned self] changes in
  switch changes {
  case .Initial:
    self.tableView.reloadData()
  case .Update(_, let deletions, let insertions, let modifications):
    // Query results have changed, so apply them to the 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: .None)
    self.tableView.endUpdates()
  case .Error(let error):
    // handle error
  }
}

func insertItem() throws {
  // Perform an interface-driven write on the main thread:
  self.collection.realm!.beginWrite()
  self.collection.insert(Item(), atIndex: 0)
  // And mirror it instantly in the UI
  self.tableView.insertRowsAtIndexPaths([NSIndexPath(forRow: 0, inSection: 0)], withRowAnimation: .Automatic)
  // Making sure the change notification doesn't apply the change a second time
  try self.collection.realm!.commitWrite(withoutNotifying: [self.notificationToken])
}

デモ

RealmTasks Fine-Grained Notifications

オープンソースとして公開されているRealmTasksの、「通知をスキップする書き込み」によりきめ細やかな通知が利用できるようになったPull Requestをご覧ください。macOS版はこちらです。

不具合の修正

以上の機能を実装中に、コレクション通知に関するいくつかの不具合を発見することができました。そのためこのバージョンの通知は以前よりも安定して動作します!

  • 書き込みトランザクションを開始した際に読み取りバージョン更新される場合にもコレクション通知が送られるようになりました。(以前はRealmの通知だけが送られていました。)
  • まれに通知の状態が不整合になってしまう問題を修正しました。
  • レースコンディションを引き起こす不具合を修正しました。
  • トランザクションをキャンセルした場合に通知が送られないように修正されました。

古いSwiftバージョンのサポート

Xcode 7.3.1とSwift 2.2のサポートはできる限り長い間続ける予定ですが、できるだけ早くXcode 8に移行することをおすすめします。


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

Read more

Realm Objective-C & Swift 2.0 – Mobile Platformをサポート

by /

Realm Objective‑CおよびRealm Swift 2.0をリリースしました。 このバージョンではRealm Mobile Platformに対応し、サーバサイドとデータの同期が可能になりました。 加えて、Swift 3の対応と不具合の修正のために非互換の変更が1つだけ含まれます。詳しくは下記をご覧ください。

Realm Mobile Platform拡張

Realm Mobile Platformのリリースのお知らせをご覧になっていない方は先にそちらをお読みいただき、その後この記事でCocoaに関する詳細を確認してください。

まず簡単にデータ同期を有効にする設定をご紹介します、

// Authenticating the User
User.authenticate(with: .google("google token"),
                  server: URL(string: "https://realm.example.com:9443")) { user, error in
  if let user = user {
    // Opening a remote Realm
    let realmURL = URL(string: "realm://realm.example.com:9080/~/userRealm")!
    let config = Realm.Configuration(syncConfiguration: (user, realmURL))
    let realm = try! Realm(configuration: config)
    // Any changes made to this Realm will be synced across all devices!
  } else if let error = error {
    // handle error
  }
}

これだけです。一度設定を有効にすれば、あとは自動的にすべてのデバイスでデータが同期されます。

ここからは技術的な詳細についてお話しします。Mobile Platformに対応するために、新しいクラスとAPIを追加しました。

同期ユーザオブジェックトと認証オブジェクト

同期ユーザはRealmを同期するための中心的な概念です。すべてのRealmはユーザに関連付けられます。ユーザはユーザ名/パスワードもしくは、Google、Facebook、iCloudなどの外部プロバイダによって認証することができます。詳しくはドキュメントのUsersセクションをご覧ください。

同期設定

Realmの同期設定を有効にするには、RLMRealmConfiguration/Realm.ConfigurationクラスのプロパティsyncConfigurationをセットします。syncConfigurationには同期ユーザとリモートRealmURL(例: realm://realm.example.com:9080/~/userRealm)のペアを渡します。詳しくはドキュメントをご覧ください。

同期マネージャとセッション

同期マネージャ(RLMSyncManager/SyncManager)はシングルトンオブジェクトで、すべての同期されたRealmを管理します。同期エンジンのログレベルの設定や、グローバルエラーのハンドリングはこのクラスを通じて行います。

それぞれの同期されたRealmはセッション(RMLSyncSession/SyncSession)に関連付けられます。セッションはRealmの状態を表します。今後、より詳細な情報が取得できるように改善される予定です。

プラットフォーム拡張はベータ版です

これまでRealmは5年かもの間、改善を繰り返し、安定した動作を獲得しました。同様にAPIを少しずつ改善していくため、プラットフォーム拡張は現在ベータ版としてリリースしています。APIは今後のリリースで変更される場合があります。

プラットフォーム拡張は、ローカルのRealmと同期されたRealmと明確に区別して設計されていますので、プラットフォーム拡張が不要な場合でも、これまでと同様にRealmを安定して利用することができます。

2.0には非互換の変更は「ほとんど」ありません

このリリースは大きな新機能を含むためにメジャーバージョンアップとなります。しかし、APIに非互換の変更はほとんど加えていません。なぜなら、直前のメジャーバージョンアップである1.0のリリースはわずか数か月前であるので、非互換のAPIに対応する時間を費やすことは避けたかったのです。 ただ1つだけ例外があります。Swift 3に対応したRealm 1.1.0を先日リリースしましたが、その際に、Errorクラスがそのままでは標準ライブラリののSwift.Errorとコンフリクトして使いづらいというフィードバックを数多くいただきました。そこで、ErrorクラスはRealmのエクステンションとしてネストした型に変更することにしました。今回のリリースにおける非互換の変更はこの1つだけです。

注意:Realm Objective-CおよびSwift 2.0はファイルフォーマットが刷新され、パフォーマンスの改善と不具合が修正されています。そのため、バージョン2.0で作られたファイルは1.x以前のバージョンからは読み込むことができなくなります。古いバージョンで作られたファイルを新しいバージョンのRealmで読み込むことは問題ありません。

関連ファイルの削除

.log.log_a.log_bという拡張子のファイルはRealmファイルに統合されたため、作られなくなりました。それにより、ファイルを開くときや、書き込みのパフォーマンスが向上し、トランザクション中に別のファイルを開く際の速度低下をなくすことができました。

不具合の修正

  • ゼロのプロパティでソートしたときにアサーションエラーが起こる問題を修正しました。
  • 同じファイルを開いている複数のプロセスがあるとき、コミットの途中で1つのプロセスがクラッシュすると、他のすべてのプロセスもクラッシュしてしまう問題を修正しました。
  • オプショナルのfloatもしくはdouble型のプロパティが既存のモデルに追加されたとき、ゼロでなく正しく初期化されるようになりました。
  • インデックスが付加されたString型のとても長いプロパティがスタックオーバーフローを引き起こす問題を修正しました。
  • 非同期クエリ、またはコレクションに対する通知において、クラッシュを引き起こすレースコンディションを修正しました。
  • 自分自身に関連付けられたオブジェクトを削除しようとした際に、データが不整合になる問題を修正しました。

Q: 新しくオープンソースとして公開されたRealm CoreストレージエンジンをRealmと組み合わせて使えますか?

もちろんです!100%完全なオープンソースになったRealmをビルドして利用することができます。インストールの手順は、例えばCocoaPodsを使った場合(pod installするだけ)よりも複雑になりますが、realm-corerealm-cocoaに記してある手順にしたがってください。

現在ocoaPodsを使って完全にソースコードからビルドできるように準備しています。楽しみにしていてください!

Xcode 7.3.1とSwift 2.2でも引き続きご利用いただけます。できるだけ早くXcode 8とSwift 3またはSwift 2.3に移行することをお勧めします。


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

Read more

Realm Mobile Platform: リアルタイムの同期と、Coreのオープンソース化

by /

2014年にRealmを起ちあげたとき、私たちの目標はSQLiteやCore Dataの代替となる技術を提供することでアプリ開発者の開発スピードを加速させることでした。2年半が経ち、Realmは10万人以上のアクティブな開発者のみなさまにご利用いただき、リリースされたアプリのインストール総数は10億を超えています。 これまでRealmを利用し、フィードバックをくださったり、さまざまな形で開発を支えてくださったコミュニティの皆さまに心より感謝いたします。

本日、Realmは新しくRealm Mobile Platformをリリースします。 Realm Mobile PlatformはiOSとAndroid向けの完全にオープンソースなクライアントサイドのデータベースに加え、リアルタイムの同期、コンフリクトの解決、イベントハンドリングといったサーバサイドの機能をシームレスに統合します。 Realm Mobile Platformを使うことで、リアルタイムの共同編集やメッセージアプリ、オフラインでも使えてオンラインになったら同期といった難しい機能を非常に簡単に実装することができます。

 

Realm Mobile Platformはベータ版として本日から提供を開始します。Realm Mobile PlatformにはDeveloper EditionとEnterprise Editionの2種類のエディションがあります。 Developer Editionは用途にかかわらず永久に無料で利用することができ、趣味のアプリや規模の小さな商用利用に適しています。 Enterprise Editionは有償ですが、試用期間は無料で利用できます。Enterprise Editionにはテクニカルサポートと保証が付属しますので、大規模な商用サービスでも安心して利用できます。詳細については後述します。 現在は、Java、Objective-C、Swiftの3つの環境で利用できます。React NativeとXamarinではまだご利用いただけません。将来的にはすべてのプラットフォームで利用可能になります。

もう一つ大きなお知らせがあります。いよいよRealm Coreをオープンソースとして公開いたします。このことによって、本日Realm Mobile Databaseのすべてのソースコードが公開されたことになります。ソースコードはすべてGitHubで公開しています。 Realm Mobile DatabaseはRealm Mobile Platformの一部としてだけでなく、これまでと同様モバイルにおけるスタンドアローンなデータベースしても私たちのもっとも重要なプロダクトです。Realm Mobile Platformと同様にこれからも改善を続けていきます。

The Realm Mobile Platform

Objects All the Way Down

Realmを利用されている方のほとんどはRealm Coreの仕組みについて意識したことがないかもしれません。しかし、私たちはRealmのもっとも重要な差別化要因はRealm Coreだと考えています。Realmのパフォーマンスと使いやすさの秘密はRealm Coreの仕組みによります。Realm Coreを利用するため、Realmにはリレーショナルデータベースとオブジェクトをマッピングするときのような複雑な仕組みは必要ありません。ただデータをオブジェクトとして素直に表現することができます。つまり、データベースとモデルクラスを完全に同一とすることができます。

このデザイン哲学を今回発表するRealm Object Serverにも適用しています。 また、「ライブオブジェクト」と呼んでいる、Realmにおいて重要な仕組みがもう一つあります。ライブオブジェクトによって、デバイス上のデータは常にサーバのデータと完全に同期します。同期の処理は自動的に、そしてシームレスに行われます。 ネットワーク通信のコードを書く必要はまったくありません。さらに、データ全体ではなく差分のみが転送されるので非常に効率的です。 Realm Mobile Platformはコンフリクトの解決もサポートします。同じオブジェクトに対して変更がコンフリクトした場合は、ルールに従って解消します。 デフォルトのルールはほとんどのユースケースに適しています。ルールのカスタマイズも簡単にできます。

Realm Mobile Platformを利用すると、ネットワーク通信のことを気にする必要はありません。そのため、アプリケーションのデータ操作だけに集中することができます。 つまり、リアルタイムな共同編集やメッセージアプリといった通常は構築することが難しいとされているアプリケーションの作成が簡単になります。 想像してみてください。ホワイトボードの編集を複数人がそれぞれのデバイスで同時に行うことができるアプリがあるとします。もっとも実装が困難なところは、複数の変更をそれぞれのUIに即座に反映することでしょう。コンフリクトも解決も同様に難しいです。同じ場所を複数人が同時に編集したり削除したりする、というのをエレガントに表示しなければなりません。 Realm Mobile Platformはそのような難しいところをすべて引き受けます。

オフラインファーストを実現する

Realm Mobile Platformはオフラインファーストなアプリケーションに対しても素晴らしいソリューションです。オフラインファーストなアプリケーションではネットワーク接続の有無にかかわらずいつでもデータが利用できることが必要ですが、Realm Mobile Databese自体がデバイス上で動作する組み込みデータベースです。そのためネットワークから切断された場合でも、アプリケーションは常にデータを利用することができます。これはRealm Mobile Databeseを単体で使う場合であっても得られる重要な利点です。

Realm Mobile Platform全体(Realm Mobile Database + Realm Object Server)を利用することでさらに大きなメリットを得ることができます。双方向の同期が自動的におこなわれるため、サーバーと接続している間は常に最新のデータを参照することができます。通信が切断された場合でも切断中の変更は再接続後に自動的にマージされ再び最新の情報にアクセスすることができます。この自動的な双方向マージにより、ユーザーは通信状態を気にすることなくアプリを使うことができます。

イベントハンドリング

Enterprise EditionのRealm Mobile Platformではサーバーサイドにおけるイベントハンドリングのフレームワークが提供されます。データの変更をトリガーにして任意の処理をサーバサイドで実行できます。 このフレームワークを用いて、デバイスで行われた変更を監視し、即座にサーバ側からレスポンスを送ることができます。 例えば、ショッピングアプリの注文画面で、クーポンコードを入力したとします。すると、クーポンオブジェクトがローカルに保存され、それは即座にサーバに同期されます。サーバ側ではその変更を検知して、クーポンコードが正しいか検証し、結果をクライアントに通知します。クライアントはそれを受けてUIを更新します。

The Realm Mobile Platform

このようにRealmのイベントハンドリングを用いて、既存のAPIやサーバのロジックと統合することができます。Realm Object ServerをAPIのブリッジやミドルウェアとして利用します。 それにより、アプリを「サーバーレス」コンピューティングに従って構築できます。個別のトリガーに対して処理を書くだけで良いのです。

本日より提供開始

前述のように、Realm Mobile Platformは2種類のエディションがあります。Developer Editionは無料で利用でき、現在はベータ版として提供しています。ドキュメントはこちらです。フィードバックはいつでもお待ちしています。 Enterprise Editionはイベントハンドリングなどの機能が含まれます。現在はクローズドベータプログラムとして提供しています。ベータプログラムへ参加するにはこちらのフォームに必要事項を記入してください。順次、ご案内を差し上げます。

Read more

Mobile Platform Supportを追加したRealm Java 2.0をリリースしました

by /

本日、Realm Mobile Platformなどの新機能を含んだRealm Java 2.0をリリースしました。

Realm Mobile Platform拡張

Realm Mobile Platformの リリースについてのお知らせをご覧になっていない方は先にそちらをお読みいただき、その後このエントリでAndroidに関する詳細を確認していただければと思います。

Realm JavaでRealm Mobile Platform拡張を使用するためには、アプリのプロジェクトのbuild.gradleファイルで以下のように有効化します。

realm {
  syncEnabled = true
}

それではデバイス間同期を有効にしたRealmの設定方法を見ていきましょう。

// ログイン
Credentials creds = Credentials.usernamePassword(username, password, true);
User.loginAsync(creds, "https://realm.example.com:9443", new User.Callback() {
  @Override
  public void onSuccess(User user) {
    // Opening a remote Realm
    // このRealmインスタンスに対するすべての変更は自動的にデバイス間で同期されます。
    SyncConfiguration config = new SyncConfiguration.Builder(user, "realm://realm.example.com/~/userRealm").build();
    Realm realm = Realm.getInstance(config);
  }

  @Override
  public void onError(ObjectServerError error) {
    // エラー処理
  }
});

たったこれだけです。このようにRealmをオープンすることで、同じユーザー情報を使用するすべてのデバイス間で自動的に変更が同期されます。

さらに詳細に見ていきましょう。Realm Mobile Platformをサポートするために、APIにいくつかのクラスを追加しています。

User & Credential

ユーザーは同期するRealmではとても重要な概念です。同期するすべてのRealmはユーザーに関連付けられます。ユーザーはユーザー名とパスワードだけでなく、Google、Facebook、iCloudなどにより認証することができます。詳細についてはドキュメントを参照してください。

Sync Configuration

SyncConfigurationクラスを用いることで、ユーザーとサーバーのURL(例: realm://realm.example.com/~/userRealm)を指定してRealmインスタンスを取得することができます。詳細についてはドキュメントを参照してください。

Sync Manager & Session

SyncManagerはすべての同期するRealmを管理するシングルトンです。現時点では共通のエラーハンドリングのために使用します。

同期するRealmはそれぞれがSessionを持ちます。Sessionを通して、同期に関する状態の情報にアクセスできます。Sessionには今後も有用な情報を追加していく計画です。

Realm Mobile Platform拡張はベータ版です

Realmの同期機能は長い時間をかけて開発された安定した基盤の上に構築されています。Realm Mobile Platformの拡張APIについてはより使いやすいものに改善していくため、現時点ではベータ版として提供することにしました。そのため、APIは将来のリリースで変更される可能性があります。

Realm Mobile Platformの拡張APIを使用しない場合は、これまで通りのスタンドアローンのRealmとして利用することができます。

拡張APIはスタンドアローンのRealmのものとは明確に区別されて設計されているため、アプリがベータ版の拡張APIに依存しているどうかはかんたんに把握することができます。

すべてのベータ版APIにはコードおよびJavadocに@Betaタグがつけられています。

2.0でのその他の変更点

本リリースはメジャーバージョンアップなので、さまざまな新機能がふくまれています。また同時に、Realm SwiftやRealm Objective-Cとより親和性を高めるための変更も含まれます。

パフォーマンス改善といくつかのバグ修正のため、本リリースではファイルフォーマットが変更されています。Realm Java 2.0以降で読み書きされたデータベースファイルは1系のバージョンでは読むことができません。以前のバージョンのファイルを2.0以降から読み書きする際には自動的に新ファイルフォーマットに移行されます。

注意: 事前に作成されたRealmファイルをアプリとともに配布している場合は、新しいファイルフォーマットへ変換してください。変換にはRealm Browserを使用することができます。

Global initializer

Realm JavaにContextを必要とするAPIがだんだんと増加していました。ContextがAPIの使い勝手を悪くしてしまう部分があったため、2.0ではグローバルな初期化APIを追加し、そこでのみContextを要求するように変更しました。

Realm.init(context)`

この変更により、さまざまなAPIで引き数からContextが削除されています。この点に関するAPIの変更は以下のとおりです。

  • RealmConfiguration.BuilderのコンストラクターからContextを削除しました。
  • RealmConfiguration.Builder.assetFile()からContextを削除しました。
  • Realm.getDefaultInstance()はデフォルトのRealmConfigurationをセットすることなく呼び出すことができるようになりました。
  • ネイティブコードの読み出しがより安定したものになりました。

グローバルな初期化は、Applicationのサブクラスで行うように実装するのが自然です。

public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        Realm.init(this);
        // その他の初期化処理
    }
}

デフォルト値

Realm Java 2.0では、オブジェクト作成のさいのデフォルト値がサポートされました。これは、以下のようにモデルクラスを定義する際にフィールドやデフォルトコンストラクタで値を指定できることを意味します。

public class Person extends RealmObject {
  private String name = "John";
  private int age;

  public Person() {
    this.age = 42;
  }
}

Person p = realm.createObject(Person.class);
p.getName(); // John
p.getAge(); // 42

デフォルト値はJSONからオブジェクトを作成する際にも適用されますが、dynamic APIを用いる場合には適用されません。

RealmLog

RealmLogクラスがAPIに追加されました。このクラスは、どの程度のログが出力する、またどのようにログを出力するかを制御することができます。Realm Mobile Platformに関するログも、全てこのクラスを通じて制御可能です。

RealmLog.clear(); // すべてのロガーを削除
RealmLog.add(new AndroidLogger(Log.DEBUG)); // 独自のロガーを追加

プライマリキーの扱いについて

デバイス間のデータ同期をサポートするため、プライマリキーに関する以下の2つの制約が新たに追加されています。

1) オブジェクトの作成の際に、必ずプライマリキーの値を指定することが必要。 2) 一旦セットされたプライマリキーの値は変更できない。

1つ目の制約は、realm.createObject(Class)に関係するものです。プライマリキーが定義されたモデルクラスのオブジェクトを作成する際は、realm.createObject(Class, Object)を使用してプライマリキーの値を指定する必要があります。

realm.copyToRealm()realm.createObjectFromJson()は従来通り使用することができます。

もし何らかの理由でプライマリキーの値を変更する必要がある場合は、変更後のプライマリキーの値を持つ新たなオブジェクトを作成し、フィールドの値をコピーする必要があります。その際、copyFromRealm()/copyToRealm()の利用を検討してください。

バグフィックスおよびその他の変更点

変更やバグフィックスの完全なリストは Changelogを参照してください。


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

Read more

Realm Objective-C & Swift 1.1.0 – Swift 3、Xcode 8に対応

by /

Xcode 7.3.1とSwift 2.2でも引き続きご利用いただけます。できるだけ早くXcode 8とSwift 3またはSwift 2.3に移行することをお勧めします。

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

このバージョンでは、Xcode 8とSwift 2.3、Swift 3.0への対応と、iOS 10、macOS 10.12、tvOS 10およびwatchOS 3をサポートしました。 また、いくつかの互換性に影響のない細かい改善と不具合の修正を含みます。変更点につきましては下記をご覧ください。

Swift 3らしいAPIの改善

ご存知のようにSwift 2.xから3への変更は非常に大きな変化を伴います。

Realm SwiftのパブリックAPIを慎重に精査し、新しい文法とAPIデザインガイドラインに従うように変更しました。ガイドラインにできるだけ従いつつも、変更が大きくなりすぎないように注意深くバランスを保つように修正しましたので、既存のコードに与える影響はそれほど大きくないはずです……?

下記にRealm SwiftがSwift 2.2から3.0に移行する際に必要な変更の例を抜粋します。

// Swift 2.2/2.3
let config = Realm.Configuration(
  schemaVersion: 1,
  migrationBlock: { migration, oldSchemaVersion in
    migration.renamePropertyForClass(Person.className(), oldName: "yearsSinceBirth", newName: "age")
    migration.enumerate(Person.className()) { oldObject, newObject in
      // Migrate Person
    }
  }
)

let realm = try! Realm(configuration: config)
let sortedDogs = realm.objects(Dog.self).filter("color = 'tan'").sorted("name")
let jim = Person()
try! realm.write {
  jim.dogs.appendContentsOf(sortedDogs)
}

// Swift 3.0
let config = Realm.Configuration(
  schemaVersion: 1,
  migrationBlock: { migration, oldSchemaVersion in
    migration.renameProperty(onType: Person.className(), from: "yearsSinceBirth", to: "age")
    migration.enumerateObjects(ofType: Person.className()) { oldObject, newObject in
      // Migrate Person
    }
  }
)

let realm = try! Realm(configuration: config)
let sortedDogs = realm.objects(Dog.self).filter("color = 'tan'").sorted(byProperty: "name")
let jim = Person()
try! realm.write {
  jim.dogs.append(objectsIn: sortedDogs)
}

複雑になるのを避けるために、ドキュメンテーションやサンプルコード、 APIドキュメントは、まもなくSwift 3を用いた内容に更新されます。

非互換の変更

  • Cocoaの標準的なNSErrorの規約に従うためmigrateRealm:は非推奨になりました。代わりにperformMigrationForConfiguration:error:を利用してください。
  • RLMResultsに対する添え字を使ったアクセス(Subscripting)はid型ではなくジェネリック型を返すようになりました。

その他の改善

  • SwiftにおいてNSNumber型のプロパティを間違って使用した場合のエラーメッセージをわかりやすくしました。
  • ビルド済み静的ライブラリの容量が減少しました。
  • 非オプショナル(null不可)プロパティに対する並べ替えのパフォーマンスが向上しました。
  • 必須プロパティに対するチェックをRealmに保存される直前まで遅延することにより、initWithValue:メソッドを使用した部分的なオブジェクトの生成ができるようになりました。

不具合の修正

  • float型もしくはdouble型のプロパティに対して、右辺が定数となる条件のクエリを発行した際に、値が間違って切り捨てられる問題を修正しました。
  • Int8Int16Int32Int64型のプロパティに対して集合関数を使用した際にクラッシュする問題を修正しました。
  • RLMArrayまたはList型のオブジェクトが生成されたスレッドとは別のスレッドで解放された際に、クラッシュを引き起こすレースコンディションを修正しました。
  • 通知に登録していたオブジェクトが解放される際に起こるクラッシュを修正しました。
  • スキーマが初期化されていない際にinitWithValue:メソッドをネストしたオブジェクトに対して使用するとクラッシュする問題を修正しました。
  • プライマリキーがRealmOptional型の場合、一度保存したキーの値を変更できてしまう問題を修正しました。

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

Read more