Docs Menu
Docs Home
/ /
Atlas Device SDK
/ /

スレッディング - Swift SDK

項目一覧

  • 従う 3 つのルール
  • バックグラウンド書き込みの実行
  • 非同期書込みの完了を待機する
  • 非同期書込みのコミットまたはキャンセル
  • スレッド間の通信
  • バックグラウンド スレッドで Realm を使用するための直列キューの作成
  • スレッド間で インスタンスを渡す
  • スレッド間で同じ Realm を使用
  • Realm の更新
  • 凍結されたオブジェクト
  • Realm のスレッドモデルの詳細
  • Gitとの比較と対比
  • 内部構造
  • 概要
  • 送信可能タイプ、非送信タイプ、スレッド付きタイプ

iOS および vOS アプリを高速で応答性を高くするには、ビジュアルを配置し、ユーザー インタラクションを処理するのに必要な時間と、データを処理し、ビジネス ロジックの実行に必要な時間とのバランスを取る必要があります。 通常、アプリ開発者はこの作業を複数のスレッドに分散します。そのため、ユーザー インターフェイスに関連するすべての作業のメイン スレッドまたは UI スレッドと、提示のために UI スレッドに送信する前に、より重いワークロードを計算するための 1 つ以上のバックグラウンド スレッドがあります。 重い作業をバックグラウンド スレッドにオフロードすることで、ワークロードのサイズに関係なく、UI スレッドの応答性が非常に高くなります。 しかし、デッドロックや競合状態などの問題を回避する、スレッドセーフでパフォーマンスが高く、維持可能なマルチスレッド コードを記述するのは非常に困難です。 Realm はこれを簡素化することを目的としています。

Tip

以下も参照してください。

10.26.0現在、 Realm は、バックグラウンド書込みを実行するための非同期書込みメソッドを提供します。 詳細: バックグラウンド書込みを実行するを参照してください。 非同期書込みでは、スレッドセーフな参照固定されたオブジェクトをスレッド間で渡す必要はありません。

このページでは、スレッド全体で邦土ファイルとオブジェクトを手動で管理する方法について説明します。 Realmは Swiftアクター の使用もサポートしています。 Swift同時実行機能を使用して邦土アクセスを管理します。 Realm のアクター サポートの概要については、「 アクターで Realm を Realmする - Swift SDK」を参照してください。

Realm のマルチスレッド アプリ用ツールを調べる前に、次の 3 つのルールを理解し、従う必要があります。

読み取りをロックしないでください。
Realm のMultiversion Concurrency Control (MVCC)アーキテクチャにより、読み取り操作のためにロックする必要がなくなります。 読み込んだ値が破損したり、部分的に変更された状態になったりすることはありません。 ロックやミューテックスを必要とせずに、任意のスレッドで同じ Realm ファイルから自由に読み取りができます。 各スレッドは読み取りを行う前にすべてのスレッドを待機する必要があるため、不必要にロックするとパフォーマンスのボトルネックが発生します。
バックグラウンド スレッドで書き込みを行う場合は、UI スレッドでの同期書き込みを避けます。
Realm ファイルにはどのスレッドからでも書き込みができますが、一度に書き込みできるのは 1 つだけです。 その結果、同期書込みトランザクション (write transaction) は相互にブロックされます。 UI スレッドで同期書込み (write) を行うと、バックグラウンド スレッドへの書込みが完了するのを待機している間にアプリが応答しなくなる可能性があります。 Device Syncはバックグラウンド スレッドで書込み (write) を実行するため、同期された Realm を持つ UI スレッドでの同期書込みを避ける必要があります。
ライブ オブジェクト、コレクション、または Realm を他のスレッドに渡さないでください。
ライブ オブジェクト、コレクション、Realm インスタンスはスレッド定義です。つまり、これらは作成されたスレッドでのみ有効です。 具体的には、ライブ インスタンスを他のスレッドに渡すことはできません。 ただし、Realm にはスレッド間でオブジェクトを共有するためのいくつかのメカニズムが用意されています。

Tip

以下も参照してください。

バージョン 10.26.0 の新機能

writeAsync を使用して、バックグラウンドでオブジェクトを追加、変更、または削除できます。

writeAsyncを使用すると、スレッドセーフな参照固定されたオブジェクトをスレッド間で渡す必要がありません。 代わりに、 realm.writeAsyncを呼び出します。 書き込みが完了または失敗した後にソース スレッドで実行されるメソッドの完了ブロックを指定できます。

バックグラウンド書込みを実行する際に考慮する必要があること

  • 非同期書込み (write) は、Realm を閉じるまたは無効にすることをブロックします

  • トランザクションを明示的にコミットまたはキャンセルできます

let realm = try! Realm()
// Query for a specific person object on the main thread
let people = realm.objects(Person.self)
let thisPerson = people.where {
$0.name == "Dachary"
}.first
// Perform an async write to add dogs to that person's dog list.
// No need to pass a thread-safe reference or frozen object.
realm.writeAsync {
thisPerson?.dogs.append(objectsIn: [
Dog(value: ["name": "Ben", "age": 13]),
Dog(value: ["name": "Lita", "age": 9]),
Dog(value: ["name": "Maui", "age": 1])
])
} onComplete: { _ in
// Confirm the three dogs were successfully added to the person's dogs list
XCTAssertEqual(thisPerson!.dogs.count, 3)
// Query for one of the dogs we added and see that it is present
let dogs = realm.objects(Dog.self)
let benDogs = dogs.where {
$0.name == "Ben"
}
XCTAssertEqual(benDogs.count, 1)
}

SDK は、Realm が現在非同期書込みを実行しているかどうかを示すBoolを提供します。 isPerformingAsynchronousWriteOperations変数は、次のいずれかを呼び出した後にtrueになります。

  • writeAsync

  • beginAsyncWrite

  • commitAsyncWrite

スケジュールされたすべての非同期書込み操作が完了するまで true のままになります。 これは true ですが、Realm を閉じるか無効にすることをブロックします。

非同期書込みを完了するには、ユーザーまたは SDK は次のいずれかを呼び出す必要があります。

writeAsyncメソッドを使用すると、SDK はトランザクションのコミットまたはキャンセルを処理します。 This provides the convenience of the async write without the need to manually keep state tied to the scope of the object. ただし、 writeAsyncブロック内では、 commitAsyncWriteまたはcancelAsyncWriteを明示的に呼び出すことができます。 これらのメソッドのいずれかを呼び出せずに戻る場合、 writeAsyncは次のいずれかになります。

  • 書込みブロック内の指示を実行した後に書込みをコミットする

  • エラーを返します

どちらの場合も、これによりwriteAsync操作が完了します。

非同期書込みトランザクションをコミットまたはキャンセルするタイミングをより詳細に制御するには、 beginAsyncWriteメソッドを使用します。 このメソッドを使用する場合は、トランザクションを明示的にコミットする必要があります。 非同期書込み (write) をコミットせずに戻ると、トランザクションがキャンセルされます。 beginAsyncWritecancelAsyncWriteに渡すことができる ID を返します。

commitAsyncWrite は書込みトランザクションを非同期にコミットします。 これは、データを Realm に永続化するステップです。 commitAsyncWriteにはonCompleteブロックが含まれます。 。 このブロックは、コミットが完了するかエラーで失敗すると、ソース スレッドで を実行します。

commitAsyncWriteを呼び出すと、すぐに が返されます。 これにより、SDK がバックグラウンド スレッドで I/O を実行している間にも、呼び出し元を続行できます。 このメソッドはcancelAsyncWriteに渡すことができる ID を返します。 これにより、完了ブロックの保留中の呼び出しがキャンセルされます。 コミット自体はキャンセルされません。

commitAsyncWriteへの連続した呼び出しをグループ化できます。 これらの呼び出しをバッチすることで、書込みパフォーマンスが向上します。特にバッチされたトランザクションが小さい場合。 グループ化トランザクションを許可するには、 isGroupingAllowedパラメータをtrueに設定します。

beginAsyncWriteまたはcommitAsyncWritecancelAsyncWriteを呼び出すことができます。 これをbeginAsyncWriteで呼び出すと、書込みトランザクション全体がキャンセルされます。 commitAsyncWriteでこれを呼び出すと、 commitAsyncWriteに渡した可能性のあるonCompleteブロックのみがキャンセルされます。 コミット自体はキャンセルされません。 キャンセルするbeginAsyncWriteまたはcommitAsyncWriteの ID が必要です。

異なるスレッドから同じ Realm ファイルにアクセスするには、アクセスが必要なすべてのスレッドで Realm インスタンスをインスタンス化する必要があります。 As long as you specify the same configuration, all realm instances will map to the same file on disk.

マルチスレッド環境で Realm を使用する際の重要なルールの 1 つは、 オブジェクトはスレッド定義であることです。他のスレッドで発生した Realm、コレクション、またはオブジェクトのインスタンスにはアクセスできません。 Realm のMultiversion Concurrency Control (MVCC)アーキテクチャでは、オブジェクトのアクティブなバージョンが常に多数存在する可能性があります。 スレッド制限により、そのスレッド内のすべての インスタンスが同じ内部バージョンになります。

スレッド間での通信が必要な場合は、ユースケースに応じていくつかのオプションがあります。

  • 2 つのスレッド上のオブジェクトを変更するには、両方のスレッドでオブジェクトをクエリします。

  • React任意のスレッドで行われた変更に対応するには、Realm の 通知 を使用し 。

  • 現在のスレッドの Realm インスタンス内の別のスレッドに発生した変更を確認するには、Realm インスタンスを更新します。

  • オブジェクトの高速で読み取り専用のビューを他のスレッドに送信するには、オブジェクトを「フリーズ」します。

  • アプリ内でオブジェクトの多くの読み取り専用ビューを保持して共有するには、Realm からオブジェクトをコピーします。

  • Realm または特定のオブジェクトのインスタンスを別のスレッドまたはアクター境界間で共有するには、Realm インスタンスまたはオブジェクトへのスレッドセーフな参照を共有します。 詳細については、「スレッドセーフリファレンスを渡す」を参照してください。

バックグラウンド スレッドで Realm を使用する場合は、シリアル キューを作成します。 Realm では、 global()キューなどの同時キューで Realm の使用をサポートしていません。

// Initialize a serial queue, and
// perform realm operations on it
let serialQueue = DispatchQueue(label: "serial-queue")
serialQueue.async {
let realm = try! Realm(configuration: .defaultConfiguration, queue: serialQueue)
// Do something with Realm on the non-main thread
}

RealmResultsList 、および管理対象Objectsのインスタンスは、スレッド定義です。 つまり、それらを作成したスレッドでのみ使用できます。 ただし、Realm は、あるスレッドで作成された インスタンスを別のスレッドにコピーできる「スレッドセーフ参照」と呼ばれるメカニズムを提供します。

バージョン 10.20.0 の新機能: @スレッドセーフ ラッパーとスレッドセーフリファレンスがSendableに準拠

Swift5.6 以降を使用している場合、 @Thread セーフ プロパティ ラッパー とスレッドセーフリファレンスの両方が送信可能に準拠してい ます。

バージョン 10.17.0 の新機能

次のように、スレッド定義された インスタンスを別のスレッドに渡すことができます。

  1. @ThreadSafeプロパティ ラッパーを使用して、元のオブジェクトを参照する変数を宣言します。 定義では、 @ThreadSafeでラップされた変数は常に任意です。

  2. @ThreadSafeでラップされた変数を他のスレッドに渡します。

  3. オプションと同様に、 @ThreadSafeでラップされた変数を使用します。 参照先のオブジェクトが Realm から削除されると、参照元の変数は nil になります。

let realm = try! Realm()
let person = Person(name: "Jane")
try! realm.write {
realm.add(person)
}
// Create thread-safe reference to person
@ThreadSafe var personRef = person
// @ThreadSafe vars are always optional. If the referenced object is deleted,
// the @ThreadSafe var will be nullified.
print("Person's name: \(personRef?.name ?? "unknown")")
// Pass the reference to a background thread
DispatchQueue(label: "background", autoreleaseFrequency: .workItem).async {
let realm = try! Realm()
try! realm.write {
// Resolve within the transaction to ensure you get the
// latest changes from other threads. If the person
// object was deleted, personRef will be nil.
guard let person = personRef else {
return // person was deleted
}
person.name = "Jane Doe"
}
}

別のスレッド上のオブジェクトを操作する別の方法は、そのスレッドでそのオブジェクトを再度クエリすることです。 しかし、オブジェクトにプライマリキーがない場合、クエリは簡単ではありません。 @ThreadSafeラッパーは、プライマリキーがあるかどうかに関係なく、任意のオブジェクトで使用できます。

次の例では、関数パラメータで@ThreadSafeを使用する方法を示しています。 これは、非同期に実行されたり、別のスレッドで実行されたりする可能性のある関数に役立ちます。

Tip

アプリがasync/awaitコンテキストで Realm にアクセスする場合は、スレッド関連のクラッシュを回避するためにコードを@MainActorでマークします。

func someLongCallToGetNewName() async -> String {
return "Janet"
}
@MainActor
func loadNameInBackground(@ThreadSafe person: Person?) async {
let newName = await someLongCallToGetNewName()
let realm = try! await Realm()
try! realm.write {
person?.name = newName
}
}
@MainActor
func createAndUpdatePerson() async {
let realm = try! await Realm()
let person = Person(name: "Jane")
try! realm.write {
realm.add(person)
}
await loadNameInBackground(person: person)
}
await createAndUpdatePerson()

Realm Swift SDK バージョン 10.17.0 以前または Objective-C では、次のように、スレッド定義された インスタンスを別のスレッドに渡すことができます。

  1. スレッドセーフ リファレンスをスレッド定義オブジェクトで初期化します。

  2. 他のスレッドまたはキューに参照を渡します。

  3. Realm.resolve(_:)を呼び出して、他のスレッドの Realm の参照を解決します。 返されたオブジェクトを通常どおり使用します。

重要

ThreadSafeReferenceは 1 回だけ解決する必要があります。 それ以外の場合、参照が解放されるまで、ソース邦土は固定されたままになります。 このため、 ThreadSafeReferenceの有効期間は短くする必要があります。

let person = Person(name: "Jane")
let realm = try! Realm()
try! realm.write {
realm.add(person)
}
// Create thread-safe reference to person
let personRef = ThreadSafeReference(to: person)
// Pass the reference to a background thread
DispatchQueue(label: "background", autoreleaseFrequency: .workItem).async {
let realm = try! Realm()
try! realm.write {
// Resolve within the transaction to ensure you get the latest changes from other threads
guard let person = realm.resolve(personRef) else {
return // person was deleted
}
person.name = "Jane Doe"
}
}

別のスレッド上のオブジェクトを操作する別の方法は、そのスレッドでそのオブジェクトを再度クエリすることです。 しかし、オブジェクトにプライマリキーがない場合、クエリは簡単ではありません。 プライマリキーがあるかどうかに関係なく、任意のオブジェクトでThreadSafeReferenceを使用できます。 リストや結果でも使用することもできます。

ダウンタイムは、 ThreadSafeReferenceにある程度のディレクティブを必要とすることです。 オブジェクトがバックグラウンド スレッドで存在しないようにするには、 DispatchQueue内のすべての内容を適切にスコープ指定されたautoreleaseFrequencyでラップする必要があります。 したがって、次のように、ポインターレートを処理するための便宜的拡張を作成すると便利です。

extension Realm {
func writeAsync<T: ThreadConfined>(_ passedObject: T, errorHandler: @escaping ((_ error: Swift.Error) -> Void) = { _ in return }, block: @escaping ((Realm, T?) -> Void)) {
let objectReference = ThreadSafeReference(to: passedObject)
let configuration = self.configuration
DispatchQueue(label: "background", autoreleaseFrequency: .workItem).async {
do {
let realm = try Realm(configuration: configuration)
try realm.write {
// Resolve within the transaction to ensure you get the latest changes from other threads
let object = realm.resolve(objectReference)
block(realm, object)
}
} catch {
errorHandler(error)
}
}
}
}

この拡張機能は Realm クラスにwriteAsync()メソッドを追加します。 このメソッドは インスタンスをバックグラウンド スレッドに渡します。

メール アプリを作成し、バックグラウンドで読み取られたメールをすべて削除したいとします。 現在、2 行のコードでそれを実行できます。 閉じる はバックグラウンド スレッドで実行され、Realm と渡されたオブジェクトの両方の独自のバージョンを受け取ることに注意してください。

let realm = try! Realm()
let readEmails = realm.objects(Email.self).where {
$0.read == true
}
realm.writeAsync(readEmails) { (realm, readEmails) in
guard let readEmails = readEmails else {
// Already deleted
return
}
realm.delete(readEmails)
}

スレッド間で Realm インスタンスを共有することはできません。

スレッド間で同じ Realm ファイルを使用するには、各スレッドで異なる Realm インスタンスを開きます。 同じ構成を使用している限り、すべての Realm インスタンスがディスク上の同じ ファイルにマッピングされます。

Realm を開くと、最新の成功した書込みコミットが反映され、更新される までそのバージョンのままになります。 つまり、Realm は次回の更新まで、別のスレッドで発生した変更を参照できません。 UI スレッド上の Realm(より正確には、任意のイベント ループ スレッド上の)は、そのスレッドのループの開始時に自動的に更新されます。 ただし、ループ スレッドに存在しない、または自動更新が無効になっている Realm インスタンスは、手動で更新する必要があります。

if (![realm autorefresh]) {
[realm refresh]
}
if (!realm.autorefresh) {
// Manually refresh
realm.refresh()
}

スレッドで区切られたライブ オブジェクトはほとんどの場合正常に動作します。 ただし、一部のアプリ(リアクティブなイベントストリームベースのアーキテクチャに基づくものなど)では、UI スレッドで最終的に終了する前に、処理のために不変のコピーを多数のスレッドに送信する必要があります。 毎回深いコピーを作成するとコストが高くなるため、Realm ではライブ インスタンスをスレッド間で共有できません。 この場合、オブジェクト、コレクション、Realm をフリーズして解凍できます。

固定化により、特定のオブジェクト、コレクション、または Realm の不変のビューが作成されます。 固定されたオブジェクト、コレクション、または Realm は引き続きディスク上に存在するため、他のスレッドに渡す際に深くコピーする必要はありません。 スレッドの問題に関係なく、固定されたオブジェクトをスレッド間で自由に共有できます。 Realm を固定すると、その子オブジェクトも固定されます。

Tip

Swift アクターでスレッドセーフリファレンスを使用する

Realm は現在、Swift アクターでthaw()を使用することをサポートしていません。 アクターの境界をまたがって Realm データを操作するには、固定されたオブジェクトの代わりにThreadSafeReferenceを使用します。 詳細については、「スレッドセーフリファレンスを渡す」を参照してください。

凍結されたオブジェクトはライブではなく、自動的に更新されません。 実質的に、停止時にオブジェクトの状態のスナップショットです。 オブジェクトを解凍すると、固定されているオブジェクトのライブ バージョンが返されます。

// Get an immutable copy of the realm that can be passed across threads
RLMRealm *frozenRealm = [realm freeze];
RLMResults *dogs = [Dog allObjectsInRealm:realm];
// You can freeze collections
RLMResults *frozenDogs = [dogs freeze];
// You can still read from frozen realms
RLMResults *frozenDogs2 = [Dog allObjectsInRealm:frozenRealm];
Dog *dog = [dogs firstObject];
// You can freeze objects
Dog *frozenDog = [dog freeze];
// To modify frozen objects, you can thaw them
// You can thaw collections
RLMResults *thawedDogs = [dogs thaw];
// You can thaw objects
Dog *thawedDog = [dog thaw];
// You can thaw frozen realms
RLMRealm *thawedRealm = [realm thaw];
let realm = try! Realm()
// Get an immutable copy of the realm that can be passed across threads
let frozenRealm = realm.freeze()
assert(frozenRealm.isFrozen)
let people = realm.objects(Person.self)
// You can freeze collections
let frozenPeople = people.freeze()
assert(frozenPeople.isFrozen)
// You can still read from frozen realms
let frozenPeople2 = frozenRealm.objects(Person.self)
assert(frozenPeople2.isFrozen)
let person = people.first!
assert(!person.realm!.isFrozen)
// You can freeze objects
let frozenPerson = person.freeze()
assert(frozenPerson.isFrozen)
// Frozen objects have a reference to a frozen realm
assert(frozenPerson.realm!.isFrozen)

固定されたオブジェクトを操作している場合、次のいずれかを実行しようとすると例外がスローされます。

  • 固定された Realm で書込みトランザクションを開始する。

  • 固定されたオブジェクトを変更します。

  • 固定された Realm、コレクション、またはオブジェクトへの変更リスナーの追加。

isFrozenを使用して、オブジェクトが固定されているかどうかを確認できます。 これは常にスレッドセーフです。

if ([realm isFrozen]) {
// ...
}
if (realm.isFrozen) {
// ...
}

凍結されたオブジェクトは、それを生成したライブ環境が開いている限り有効のままです。 したがって、すべてのスレッドが固定されたオブジェクトの処理を完了するまで、ライブ邦土を閉じないようにします。 ライブ Realm が閉じられる前に、固定された Realm を閉じることができます。

重要

固定オブジェクトのキャッシュについて

固定オブジェクトがキャッシュされすぎると、Realm ファイルのサイズに悪影響が及ぶ可能性があります。 「多すぎる」は、特定のターゲット デバイスと Realm オブジェクトのサイズによって異なります。 多数のバージョンをキャッシュする必要がある場合は、Realm から必要なものをコピーすることを検討してください。

固定されたオブジェクトを変更するには、オブジェクトを解凍する必要があります。 あるいは、解凍されていない Realm でその をクエリしてから変更することもできます。 ライブ オブジェクト、コレクション、または Realm でthawを呼び出すと、それ自体が返されます。

オブジェクトまたはコレクションを解凍すると、参照する Realm も解凍されます。

// Read from a frozen realm
let frozenPeople = frozenRealm.objects(Person.self)
// The collection that we pull from the frozen realm is also frozen
assert(frozenPeople.isFrozen)
// Get an individual person from the collection
let frozenPerson = frozenPeople.first!
// To modify the person, you must first thaw it
// You can also thaw collections and realms
let thawedPerson = frozenPerson.thaw()
// Check to make sure this person is valid. An object is
// invalidated when it is deleted from its managing realm,
// or when its managing realm has invalidate() called on it.
assert(thawedPerson?.isInvalidated == false)
// Thawing the person also thaws the frozen realm it references
assert(thawedPerson!.realm!.isFrozen == false)
// Let's make the code easier to follow by naming the thawed realm
let thawedRealm = thawedPerson!.realm!
// Now, you can modify the todo
try! thawedRealm.write {
thawedPerson!.name = "John Michael Kane"
}

固定のコレクションに追加する場合は、追加するコレクションとオブジェクトの両方を解凍する必要があります。 この例では、固定された Realm 内の 2 つのオブジェクトをクエリします。

  • ドキュメント オブジェクトのListプロパティを持つ ロール オブジェクト

  • 犬オブジェクト

パーソナルのドキュメント リスト コレクションにドキュメントを追加する前に、両方のオブジェクトを解凍する必要があります。 Realmが

固定されたオブジェクトをスレッド間で渡す場合も同じルールが適用されます。 一般的なケースとして、バックグラウンド スレッドで関数を呼び出して、UI をブロックする代わりに処理を実行する場合があります。

// Get a copy of frozen objects.
// Here, we're getting them from a frozen realm,
// but you might also be passing them across threads.
let frozenTimmy = frozenRealm.objects(Person.self).where {
$0.name == "Timmy"
}.first!
let frozenLassie = frozenRealm.objects(Dog.self).where {
$0.name == "Lassie"
}.first!
// Confirm the objects are frozen.
assert(frozenTimmy.isFrozen == true)
assert(frozenLassie.isFrozen == true)
// Thaw the frozen objects. You must thaw both the object
// you want to append and the collection you want to append it to.
let thawedTimmy = frozenTimmy.thaw()
let thawedLassie = frozenLassie.thaw()
let realm = try! Realm()
try! realm.write {
thawedTimmy?.dogs.append(thawedLassie!)
}
XCTAssertEqual(thawedTimmy?.dogs.first?.name, "Lassie")

Realm は マルチバージョン同時実行制御 (MVCC) により、安全で高速、ロックフリーの同時アクセスを提供します。 アーキテクチャ。

Git のような分散バージョン管理システムに理解がある場合 、MVCC について直感的に理解しているかもしれません。Git の 2 つの基本要素は次のとおりです。

  • アトミックな書込みである コミット 。

  • ブランチはコミット履歴の異なるバージョンです。

同様に、Realm にはトランザクションの形式でアトミックにコミットされた書込み (write) があります。 Realm には、ブランチと同様に、常に多くの異なるバージョンの履歴があります。

フォークを通じて分散と相違をアクティブにサポートする Git とは異なり、Realm には常に最新バージョンが 1 つだけあり、常にその最新バージョンのヘッドに書込まれます。 Realm は以前のバージョンに書込むことはできません。 つまり、データは 1 つの最新バージョンの真実のバージョンに変換されます。

Realm は B+ ツリー を使用して実装されています データ構造。最上位の ノードは Realm のバージョンを表します。子ノードは、そのバージョンの Realm 内のオブジェクトです。 Realm には最新バージョンへのポインターがあります。これは、Git が ヘッドコミット へのポインターを持っているのと同様です。

Realm はコピーオンライト手法を使用して 分離 を確保します と の 耐久性 。変更を加えると、Realm は書き込みのためにツリーの関連部分をコピーします。 その後、Realm は 2 つのフェーズで変更をコミットします。

  • Realm は変更をディスクに書き込み、成功を確認します。

  • 次に、Realm は最新バージョンのポインターを新しく書込まれたバージョンを指すように設定します。

この 2 段階のコミット プロセスにより、書込み (write) が部分的に失敗した場合でも、ツリーの関連する部分のコピーに対して変更が行われていたため、元のバージョンは一切破損しないことが保証されます。 同様に、Realm のルートポインターは、新しいバージョンの有効性が保証されるまで、元のバージョンを指します。

次の図は、コミット プロセスを示しています。

Realm は書き込み用にツリーの関連部分をコピーし、ポインターを更新して最新バージョンに置き換えます。
クリックして拡大します
  1. Realm はツリーとして構成されています。 Realm には最新バージョン V1 へのポインターがあります。

  2. 書き込み時に、Realm は V1 に基づいて新しいバージョン V2 を作成します。 Realm は変更対象のオブジェクトのコピー(A 1 、C 1 )を作成しますが、変更されていないオブジェクトへのリンクは引き続き元のバージョン(B、D)を指します。

  3. コミットを検証した後、Realm はポインターを新しい最新バージョン(V2)に更新します。 その後、Realm はツリーに接続されなくなった古いノードを破棄します。

Realm はメモリ マッピングなどのゼロコピー メソッドを使用してデータを処理します。 Realm から値を読み取る場合、ほぼそのコピーではなく、実際のディスク上の値が表示されます。 これがライブ オブジェクトの基盤です。 これは、ディスクへの書き込みが検証された後に、Realm ヘッダー ポインターを新しいバージョンを指すように設定できる理由でもあります。

  • Realm では、次の 3 つのルールに従う場合、簡単かつ安全なマルチスレッド コードが有効になります。

    • 読み取りをロックしないでください

    • バックグラウンド スレッドで書き込みを行う場合やDevice Syncを使用する場合に、UI スレッドでの書き込みを回避する

    • ライブ オブジェクトを他のスレッドに渡さないでください。

  • ユースケースごとにスレッド間でオブジェクトを共有する適切な方法があります。

  • Realm インスタンス内の他のスレッドに加えられた変更を確認するには、「ループ」スレッドに存在しない、または自動更新が無効になっている Realm インスタンスを手動で更新する必要があります。

  • リアクティブなイベントストリームベースのアーキテクチャに基づくアプリでは、オブジェクト、コレクション、Realm をフリーズして、シャットダウンしたコピーを処理用の別のスレッドに効率的に渡すことができます。

  • Realm のマルチバージョン同時実行制御(MVCC)アーキテクチャは、Git の と同様です。 Git と違い、Realm では各 Realm に対して正確な最新バージョンが 1 つだけです。

  • Realm は 2 つのステージでコミットされ、分離と耐久性を保証します。

Realm Swift SDK パブリック API には、次の 3 つの大きなカテゴリに分類されるタイプが含まれています。

  • 送信可能

  • 送信不可、およびスレッド定義なし

  • スレッドのみ

送信可能ではなく、スレッドが限定されない型をスレッド間で共有できますが、これらは同期する必要があります。

スレッド定義型は、固定されていない限り、分離コンテキストに制限されます。 同期を使用しても、これらのコンテキスト間でそれらを渡すことはできません。

送信可能
Non-Sendable
スレッド構成
任意の BSON
RMAppConfiguration
AnyRealmCollection
AsyncOpen
RMFindOneAndModifyOptions
AnyRealmValue
AsyncOpenSubscription
RMFindOptions
リスト
RMAAPIKeyAuth
RMNetworkTransport
Map
RMApp
RMRequest
MutableSet
RLMAsyncOpenTask
RMResponse
プロジェクション
RMchangeStream
RMSyncConfiguration
RRMArray
RMCompensatedWriteInfo
RMSyncTimeoutOptions
RMchangeStream
RLMCredentials
RRMDictionary
RMDecimal128
RRMDictionary変更
RLMEmailPasswordAuth
RM埋め込みオブジェクト
RMMaxKey
RMLinkingObjects
RLMMinKey
RMObject
RMMongoClient
RMPropertyCheck
RMMongoCollection
RLMRealm
RMMongoDatabase
RMResults
RMObjectId
RLMSection
RObjectSchema
RLMSectionedResults
RMProgressNotification
RLMSectionedResultschangeset
RMProgressNotificationToken
RMSet
RMProperty
RMSyncSubscription
RLMPropertyDescriptor
RMSyncSubscriptionSet
RPMProviderClient
Realm任意
RLMpushClient
RealmProperty
RLMSschema
RLMSortDescriptor
RMSyncErrorActionToken
RMSyncManager
RRMSyncSession
RMThreadセーフリファレンス
RLMUpdateResult
RLMuser
RLMuserAPIKey
RLMuserIdentity
RLMuserProfile
スレッドセーフ

戻る

削除