Docs Menu
Docs Home
/ /
Atlas Device SDK
/ /

オブジェクトモデルの変更 - Swift SDK

項目一覧

  • Overview
  • スキーマ バージョン
  • 移行
  • スキーマの自動更新
  • プロパティを追加する
  • プロパティを削除する
  • スキーマの手動移行
  • プロパティの名前を変更する
  • プロパティを変更
  • オブジェクトから埋め込みオブジェクトへの変換
  • その他の移行例

注意

同期された Realm のスキーマ プロパティの変更

次のページでは、ローカル Realm のスキーマ プロパティを変更する方法を示します。 同期された Realm のスキーマ プロパティ変更する方法を学びます。

オブジェクト スキーマを更新するときは、スキーマのバージョンを増やして移行を実行する必要があります。

Tip

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

このページでは、一般的な Swift と Objective-C の移行例を取り上げます。 SwiftUI で Realm を使用している場合は、 SwiftUI 固有の移行例 を参照してください。

スキーマ更新によってオプションのプロパティが追加されるか、プロパティが削除される場合、Realm は移行を自動的に実行できます。 schemaVersionを増やす必要があるだけです。

より複雑なスキーマ更新では、 migrationBlockで移行ロジックを手動で指定する必要もあります。 これには、次のような変更が含まれる場合があります。

  • デフォルト値を入力する必要がある必須プロパティの追加

  • フィールドの組み合わせ

  • フィールドの名前を変更する

  • フィールドの型の変更

  • オブジェクトから埋め込みオブジェクトへの変換

Tip

開発中のバイパス移行

アプリケーションを開発またはデバッグする際には、Realm を移行するのではなく、Realm を削除することをお勧めします。 スキーマの不一致により移行が必要になる場合に、データベースを自動的に削除するには、 deleteRealmIfMigrationNetedフラグを使用します。

このフラグをtrueに設定して本番環境にアプリをリリース しないでください 。

スキーマ バージョンは、ある時点におけるRealm スキーマの状態を識別します。 Realm は各 Realm のスキーマ バージョンを追跡し、それを使用して各 Realm 内のオブジェクトを正しいスキーマにマッピングします。

スキーマ バージョンは、Realm を開くときに Realm 構成に含めることができる整数です。 クライアント アプリケーションが Realm を開くときにバージョン番号を指定しない場合、Realm はデフォルトでバージョン0になります。

重要

バージョンを単調に増加させる

移行によって、Realm をより高いスキーマ バージョンに更新する必要があります。 Realm は、Realm の現在のバージョンよりも低いスキーマ バージョンでクライアント アプリケーションが Realm を開き、または指定されたスキーマ バージョンが Realm の現在のバージョンと同じであるが、異なるオブジェクト スキーマを含む場合にエラーをスローします。

ローカル移行とは、別の Realm と自動的に同期しない Realm の移行です。 ローカル移行では、既存の Realm スキーマ、バージョン、およびオブジェクトにアクセスでき、Realm を新しいスキーマ バージョンに段階的に更新するロジックを定義します。 ローカル移行を実行するには、現在のバージョンよりも高い新しいスキーマ バージョンを指定し、古くなった Realm を開くときに移行機能を提供する必要があります。

iOS では、手動移行を使用してスキーマの変更を反映するように基礎となるデータを更新できます。 このような手動移行中に、スキーマに追加または削除されるときに、新しいプロパティと削除されたプロパティを定義できます。

Realm は追加されたプロパティを自動的に移行できますが、これらを変更するときに更新されたスキーマ バージョンを指定する必要があります。

注意

Realm は、新しい必須プロパティの値を自動的に設定しません。 新しい必須プロパティにデフォルト値を設定するには、移行ブロックを使用する必要があります。 新しい任意プロパティの場合、既存のレコードは null 値を持つことができます。 つまり、オプションのプロパティを追加するときに移行ブロックは必要ありません。

スキーマ バージョン1を使用する Realm には、名、姓、および年数のプロパティを持つPersonオブジェクトタイプがあります。

// In the first version of the app, the Person model
// has separate fields for first and last names,
// and an age property.
@interface Person : RLMObject
@property NSString *firstName;
@property NSString *lastName;
@property int age;
@end
@implementation Person
+ (NSArray<NSString *> *)requiredProperties {
return @[@"firstName", @"lastName", @"age"];
}
@end
// In the first version of the app, the Person model
// has separate fields for first and last names,
// and an age property.
class Person: Object {
@Persisted var firstName = ""
@Persisted var lastName = ""
@Persisted var age = 0
}

開発者は、 Personクラスにemailフィールドが必要であると判断し、スキーマを更新します。

// In a new version, you add a property
// on the Person model.
@interface Person : RLMObject
@property NSString *firstName;
@property NSString *lastName;
// Add a new "email" property.
@property NSString *email;
// New properties can be migrated
// automatically, but must update the schema version.
@property int age;
@end
@implementation Person
+ (NSArray<NSString *> *)requiredProperties {
return @[@"firstName", @"lastName", @"email", @"age"];
}
@end
// In a new version, you add a property
// on the Person model.
class Person: Object {
@Persisted var firstName = ""
@Persisted var lastName = ""
// Add a new "email" property.
@Persisted var email: String?
// New properties can be migrated
// automatically, but must update the schema version.
@Persisted var age = 0
}

Realm は、更新されたPersonスキーマに準拠するように Realm を自動的に移行します。 ただし、開発者は Realm のスキーマ バージョンを2に設定する必要があります。

// When you open the realm, specify that the schema
// is now using a newer version.
RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init];
// Set the new schema version
config.schemaVersion = 2;
// Use this configuration when opening realms
[RLMRealmConfiguration setDefaultConfiguration:config];
RLMRealm *realm = [RLMRealm defaultRealm];
// When you open the realm, specify that the schema
// is now using a newer version.
let config = Realm.Configuration(
schemaVersion: 2)
// Use this configuration when opening realms
Realm.Configuration.defaultConfiguration = config
let realm = try! Realm()

スキーマからプロパティを削除するには、オブジェクトのクラスからプロパティを削除し、Realm の構成オブジェクトのschemaVersionを設定します。 Deleting a property will not impact existing objects.

スキーマ バージョン1を使用する Realm には、名、姓、および年数のプロパティを持つPersonオブジェクトタイプがあります。

// In the first version of the app, the Person model
// has separate fields for first and last names,
// and an age property.
@interface Person : RLMObject
@property NSString *firstName;
@property NSString *lastName;
@property int age;
@end
@implementation Person
+ (NSArray<NSString *> *)requiredProperties {
return @[@"firstName", @"lastName", @"age"];
}
@end
// In the first version of the app, the Person model
// has separate fields for first and last names,
// and an age property.
class Person: Object {
@Persisted var firstName = ""
@Persisted var lastName = ""
@Persisted var age = 0
}

開発者は、 Personにはageフィールドが不要と判断され、スキーマを更新します。

// In a new version, you remove a property
// on the Person model.
@interface Person : RLMObject
@property NSString *firstName;
@property NSString *lastName;
// Remove the "age" property.
// @property int age;
// Removed properties can be migrated
// automatically, but must update the schema version.
@end
@implementation Person
+ (NSArray<NSString *> *)requiredProperties {
return @[@"firstName", @"lastName"];
}
@end
// In a new version, you remove a property
// on the Person model.
class Person: Object {
@Persisted var firstName = ""
@Persisted var lastName = ""
// Remove the "age" property.
// @Persisted var age = 0
// Removed properties can be migrated
// automatically, but must update the schema version.
}

Realm は、更新されたPersonスキーマに準拠するように Realm を自動的に移行します。 ただし、開発者は Realm のスキーマ バージョンを2に設定する必要があります。

// When you open the realm, specify that the schema
// is now using a newer version.
RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init];
// Set the new schema version
config.schemaVersion = 2;
// Use this configuration when opening realms
[RLMRealmConfiguration setDefaultConfiguration:config];
RLMRealm *realm = [RLMRealm defaultRealm];
// When you open the realm, specify that the schema
// is now using a newer version.
let config = Realm.Configuration(
schemaVersion: 2)
// Use this configuration when opening realms
Realm.Configuration.defaultConfiguration = config
let realm = try! Realm()

Tip

SwiftUI 開発者は、プロパティを追加または削除するときに移行が必要であるというエラーが表示される場合があります。 これは、SwiftUI のライフサイクルに関連しています。 ビューは配置され、 .environment修飾子によって構成が設定されます。

このような状況で移行エラーを解決するには、 Realm.Configuration(schemaVersion: <Your Incremented Version>)ObservedResultsコンストラクターに渡します。

より複雑なスキーマ更新の場合、Realm では特定のオブジェクトの古いインスタンスを新しいスキーマに手動で移行する必要があります。

移行中にプロパティの名前を変更するには、 Migration.renameProperty(onType:from:to:) メソッドを使用します 使用して複数のドキュメントを挿入できます。

Realm は、名前変更操作中に新しい null 可能性またはインデックス作成設定を適用します。

migrationBlock内でageの名前をyearsSinceBirthに変更します。

RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init];
config.schemaVersion = 2;
config.migrationBlock = ^(RLMMigration * _Nonnull migration, uint64_t oldSchemaVersion) {
if (oldSchemaVersion < 2) {
// Rename the "age" property to "yearsSinceBirth".
// The renaming operation should be done outside of calls to `enumerateObjects(ofType: _:)`.
[migration renamePropertyForClass:[Person className] oldName:@"age" newName:@"yearsSinceBirth"];
}
};
let config = Realm.Configuration(
schemaVersion: 2,
migrationBlock: { migration, oldSchemaVersion in
if oldSchemaVersion < 2 {
// Rename the "age" property to "yearsSinceBirth".
// The renaming operation should be done outside of calls to `enumerateObjects(ofType: _:)`.
migration.renameProperty(onType: Person.className(), from: "age", to: "yearsSinceBirth")
}
})

Tip

移行が必要な場合は、 deleteRealmIfMigrationNetedメソッドを使用してRealmを削除できます。 これは、開発中に迅速に反復処理する必要があり、移行を実行したくない場合に役立ちます。

カスタム移行ロジックを定義するには、Realm 開く ときに 構成 の migrationBlock プロパティを設定します。

移行ブロックには、移行を実行するために使用できる移行オブジェクトが与えられます。 移行オブジェクトのenumObjects( ofType:_:)メソッドを使用して、Realm 内の特定の Realm タイプのすべてのインスタンスを反復処理し、更新できます。

スキーマ バージョン1を使用する Realm には、氏名用に別々のフィールドを持つPersonオブジェクトタイプがあります。

// In the first version of the app, the Person model
// has separate fields for first and last names,
// and an age property.
@interface Person : RLMObject
@property NSString *firstName;
@property NSString *lastName;
@property int age;
@end
@implementation Person
+ (NSArray<NSString *> *)requiredProperties {
return @[@"firstName", @"lastName", @"age"];
}
@end
// In the first version of the app, the Person model
// has separate fields for first and last names,
// and an age property.
class Person: Object {
@Persisted var firstName = ""
@Persisted var lastName = ""
@Persisted var age = 0
}

開発者は、 Personクラスで個別のfirstNameフィールドとlastNameフィールドではなく、結合されたfullNameフィールドを使用する必要があると判断し、スキーマを更新します。

更新された スキーマに準拠するように RealmPerson を移行するには、開発者は Realm のスキーマ バージョンを2 fullNameに設定し、既存のfirstName プロパティとlastName プロパティに基づいて の値を設定するための移行関数を定義します。 。

// In version 2, the Person model has one
// combined field for the full name and age as a Int.
// A manual migration will be required to convert from
// version 1 to this version.
@interface Person : RLMObject
@property NSString *fullName;
@property int age;
@end
@implementation Person
+ (NSArray<NSString *> *)requiredProperties {
return @[@"fullName", @"age"];
}
@end
RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init];
// Set the new schema version
config.schemaVersion = 2;
config.migrationBlock = ^(RLMMigration * _Nonnull migration, uint64_t oldSchemaVersion) {
if (oldSchemaVersion < 2) {
// Iterate over every 'Person' object stored in the Realm file to
// apply the migration
[migration enumerateObjects:[Person className]
block:^(RLMObject * _Nullable oldObject, RLMObject * _Nullable newObject) {
// Combine name fields into a single field
newObject[@"fullName"] = [NSString stringWithFormat:@"%@ %@",
oldObject[@"firstName"],
oldObject[@"lastName"]];
}];
}
};
// Tell Realm to use this new configuration object for the default Realm
[RLMRealmConfiguration setDefaultConfiguration:config];
// Now that we've told Realm how to handle the schema change, opening the realm
// will automatically perform the migration
RLMRealm *realm = [RLMRealm defaultRealm];
// In version 2, the Person model has one
// combined field for the full name and age as a Int.
// A manual migration will be required to convert from
// version 1 to this version.
class Person: Object {
@Persisted var fullName = ""
@Persisted var age = 0
}
// In application(_:didFinishLaunchingWithOptions:)
let config = Realm.Configuration(
schemaVersion: 2, // Set the new schema version.
migrationBlock: { migration, oldSchemaVersion in
if oldSchemaVersion < 2 {
// The enumerateObjects(ofType:_:) method iterates over
// every Person object stored in the Realm file to apply the migration
migration.enumerateObjects(ofType: Person.className()) { oldObject, newObject in
// combine name fields into a single field
let firstName = oldObject!["firstName"] as? String
let lastName = oldObject!["lastName"] as? String
newObject!["fullName"] = "\(firstName!) \(lastName!)"
}
}
}
)
// Tell Realm to use this new configuration object for the default Realm
Realm.Configuration.defaultConfiguration = config
// Now that we've told Realm how to handle the schema change, opening the file
// will automatically perform the migration
let realm = try! Realm()

その後、開発者はage フィールドが ではなくString Intであると判断し、スキーマを更新します。

更新されたPersonスキーマに準拠するように Realm を移行するには、開発者は Realm のスキーマ バージョンを3に設定し、移行関数に条件付きを追加して、以前のバージョンから新しいバージョンに移行する方法を定義します。

// In version 3, the Person model has one
// combined field for the full name and age as a String.
// A manual migration will be required to convert from
// version 2 to this version.
@interface Person : RLMObject
@property NSString *fullName;
@property NSString *age;
@end
@implementation Person
+ (NSArray<NSString *> *)requiredProperties {
return @[@"fullName", @"age"];
}
@end
RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init];
// Set the new schema version
config.schemaVersion = 3;
config.migrationBlock = ^(RLMMigration * _Nonnull migration, uint64_t oldSchemaVersion) {
if (oldSchemaVersion < 2) {
// Previous Migration.
[migration enumerateObjects:[Person className]
block:^(RLMObject * _Nullable oldObject, RLMObject * _Nullable newObject) {
newObject[@"fullName"] = [NSString stringWithFormat:@"%@ %@",
oldObject[@"firstName"],
oldObject[@"lastName"]];
}];
}
if (oldSchemaVersion < 3) {
// New Migration
[migration enumerateObjects:[Person className]
block:^(RLMObject * _Nullable oldObject, RLMObject * _Nullable newObject) {
// Make age a String instead of an Int
newObject[@"age"] = [oldObject[@"age"] stringValue];
}];
}
};
// Tell Realm to use this new configuration object for the default Realm
[RLMRealmConfiguration setDefaultConfiguration:config];
// Now that we've told Realm how to handle the schema change, opening the realm
// will automatically perform the migration
RLMRealm *realm = [RLMRealm defaultRealm];
// In version 3, the Person model has one
// combined field for the full name and age as a String.
// A manual migration will be required to convert from
// version 2 to this version.
class Person: Object {
@Persisted var fullName = ""
@Persisted var age = "0"
}
// In application(_:didFinishLaunchingWithOptions:)
let config = Realm.Configuration(
schemaVersion: 3, // Set the new schema version.
migrationBlock: { migration, oldSchemaVersion in
if oldSchemaVersion < 2 {
// Previous Migration.
migration.enumerateObjects(ofType: Person.className()) { oldObject, newObject in
let firstName = oldObject!["firstName"] as? String
let lastName = oldObject!["lastName"] as? String
newObject!["fullName"] = "\(firstName!) \(lastName!)"
}
}
if oldSchemaVersion < 3 {
// New Migration.
migration.enumerateObjects(ofType: Person.className()) { oldObject, newObject in
// Make age a String instead of an Int
newObject!["age"] = "\(oldObject!["age"] ?? 0)"
}
}
}
)
// Tell Realm to use this new configuration object for the default Realm
Realm.Configuration.defaultConfiguration = config
// Now that we've told Realm how to handle the schema change, opening the file
// will automatically perform the migration
let realm = try! Realm()

Tip

順次移行

移行ブロックでif (oldSchemaVersion < X)ステートメントをネストしたりスキップしたりしないでください。 これにより、クライアントがどのスキーマ バージョンから開始するかに関係なく、すべての更新を正しい順序で適用できるようになります。 目的は、古いスキーマ バージョンのデータを現在のスキーマと一致するように変換できる移行ロジックを定義することです。

埋め込みオブジェクトは、親オブジェクトと独立して存在することはできません。 オブジェクトを 埋め込みオブジェクトに変更する場合、移行ブロックは、すべての埋め込みオブジェクトが親オブジェクトへのバックリンクを 1 つだけ確保する必要があります。 バックリンクが存在しない場合、または複数のバックリンクがある場合、次の例外が発生します。

At least one object does not have a backlink (data would get lost).
At least one object does have multiple backlinks.

Tip

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

Realm-swift リポジトリでその他の移行例を確認してください。

戻る

サポートされているタイプ