Menu Docs
Página inicial do Docs
/ /
Atlas Device SDKs
/ /

Alterar um modelo de objeto - Swift SDK

Nesta página

  • Visão geral
  • Versão do esquema
  • Migrações
  • Atualize esquemas automaticamente
  • Adicionar uma propriedade
  • Excluir uma propriedade
  • Migre esquemas manualmente
  • Renomear uma propriedade
  • Modifique propriedades
  • Converta de objeto para objeto integrado
  • Exemplos adicionais de migração

Observação

Modificar Propriedades do Esquema de um Domínio Sincronizado

A página seguinte demonstra como modificar as propriedades do esquema de um Realm local. Saiba como modificar as propriedades do esquema de um Realm sincronizado.

Ao atualizar o esquema de objetos, você deve incrementar a versão do esquema e executar uma migração.

Dica

Veja também:

Esta página fornece exemplos gerais de migração para Swift e Objective-C. Se você estiver usando o Realm com o SwiftUI, consulte os exemplos de migração específicos do SwiftUI.

Se a atualização do esquema adicionar propriedades opcionais ou remover propriedades, o Realm poderá executar a migração automaticamente. Basta incrementar o schemaVersion.

Para atualizações de esquema mais complexas, você também deve especificar manualmente a lógica de migração em um migrationBlock. Isso pode incluir alterações como:

  • Adicionando propriedades necessárias que devem ser preenchidas com valores padrão

  • Combinando campos

  • Renomeando um campo

  • Como alterar o tipo de campo

  • Convertendo de um objeto para um objeto incorporado

Dica

Ignorar migração durante o desenvolvimento

Ao desenvolver ou depurar seu aplicativo, talvez você prefira excluir o Realm em vez de migrá-lo. Use o sinalizador deleteRealmifMigrationNeeded para excluir o banco de dados automaticamente quando uma incompatibilidade de esquema exigir uma migração.

Nunca libere um aplicativo para produção com esta sinalização definida como true.

Uma versão de esquema identifica o estado de um Realm Schema em um determinado momento. O Realm controla a versão do esquema de cada realm e o usa para mapear os objetos em cada realm para o esquema correto.

As versões de esquema são inteiros que você pode incluir na configuração do território quando você abre um domínio. Se um aplicativo cliente não especificar um número de versão quando abrir um domínio, o domínio assumirá como padrão a versão 0.

Importante

Incrementar versões monotonicamente

As migrações devem atualizar um realm para uma versão superior do esquema. O Realm irá gerar um erro se um aplicativo cliente abrir um realm com uma versão do esquema inferior à versão atual do realm ou se a versão do esquema especificada for igual à versão atual do realm, mas incluir esquemas de objetos diferentes.

Uma migração local é uma migração para um domínio que não é sincronizado automaticamente com outro domínio. As migrações locais têm acesso ao domínio schema, à versão e aos objetos existentes e definem a lógica que atualiza incrementalmente o domínio para sua nova versão do esquema. Para realizar uma migração local, você precisa especificar uma nova versão do esquema que seja superior à versão atual e fornecer uma função de migração ao abrir o domínio desatualizado.

No iOS, você pode atualizar os dados subjacentes para refletir as alterações de esquema usando migrações manuais. Durante essa migração manual, você pode definir propriedades novas e excluídas quando elas são adicionadas ou removidas do esquema.

O Realm pode migrar automaticamente as propriedades adicionadas, mas você deve especificar uma versão atualizada do esquema ao fazer essas mudanças.

Observação

O Realm não define valores automaticamente para novas propriedades obrigatórias. Você deve usar um bloco de migração para configurar valores padrão para novas propriedades obrigatórias. Para novas propriedades opcionais, os registros existentes podem ter valores nulos. Isso significa que você não precisa de um bloco de migração ao adicionar propriedades opcionais.

Exemplo

Um Realm que utiliza a versão 1 do esquema tem um tipo de objeto Person com propriedades de nome, sobrenome e idade:

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

O desenvolvedor decide que a classe Person precisa de um campo email e atualiza o esquema.

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

O Realm migra automaticamente o domínio para estar em conformidade com o esquema Person atualizado. Mas o desenvolvedor deve definir a versão do esquema do Realm como 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()

Para excluir uma propriedade de um esquema, remova a propriedade da classe do objeto e defina um schemaVersion do objeto de configuração do Realm. Excluir uma propriedade não afetará os objetos existentes.

Exemplo

Um Realm que utiliza a versão 1 do esquema tem um tipo de objeto Person com propriedades de nome, sobrenome e idade:

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

O desenvolvedor decide que Person não precisa do campo age e atualiza o esquema.

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

O Realm migra automaticamente o domínio para estar em conformidade com o esquema Person atualizado. Mas o desenvolvedor deve definir a versão do esquema do Realm como 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()

Dica

Os desenvolvedores do SwiftUI podem ver um erro informando que uma migração é necessária ao adicionar ou excluir propriedades. Isso está relacionado ao ciclo de vida do SwiftUI. As visualizações são dispostas e, em seguida, o modificador .environment define a configuração.

Para resolver um erro de migração nessas circunstâncias, passe Realm.Configuration(schemaVersion: <Your Incremented Version>) para o construtor ObservedResults.

Para atualizações de esquema mais complexas, o Realm exige uma migração manual para instâncias antigas de um determinado objeto para o novo esquema.

Para renomear uma propriedade durante uma migração, use Migration.renameProperty(onType:from:to:) como método.

O Realm aplica quaisquer novas configurações de nulidade ou indexação durante a operação de renomeação.

Exemplo

Renomeie age para yearsSinceBirth em um MigrationBlock.

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

Dica

Você pode usar o método deleteRealmIfMigrationNeeded para excluir o realm se ele exigir uma migração. Isso pode ser útil durante o desenvolvimento quando você precisar iterar rapidamente e não quiser fazer a migração.

Para definir a lógica de migração personalizada, defina a propriedade migrationBlock da configuração ao abrir um Realm.

O bloco de migração recebe um objeto de migração que você pode usar para realizar a migração. Você pode usar o método enumerateObjects(ofType:_:) do objeto de migração para iterar e atualizar todas as instâncias de um determinado tipo de Realm no Realm.

Exemplo

Um Realm que usa a versão 1 do esquema tem um tipo de objeto Person que tem campos separados para nomes e sobrenomes:

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

O desenvolvedor decide que a classe Person deve utilizar um campo fullName combinado em vez dos campos firstName e lastName separados e atualiza o esquema.

Para migrar o Realm para estar em conformidade com o esquema Person atualizado, o desenvolvedor define a versão do esquema do Realm como 2 e define uma função de migração para configurar o valor de fullName com base nas propriedades firstName e lastName existentes.

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

Mais tarde, o desenvolvedor decide que o campo age deve ser do tipo String em vez de Int e atualiza o esquema.

Para migrar o Realm para estar em conformidade com o esquema Person atualizado, o desenvolvedor define a versão do esquema do Realm como 3 e adiciona uma condicional à função de migração para que a função defina como migrar de qualquer versão anterior para a mais recente.

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

Dica

Migrações lineares

Evite aninhar ou ignorar as instruções if (oldSchemaVersion < X) nos blocos de migração. Isso garante que todas as atualizações possam ser aplicadas na ordem correta, independentemente da versão do esquema a partir da qual um cliente é iniciado. O objetivo é definir a lógica de migração que pode transformar os dados de qualquer versão desatualizada do esquema para que correspondam ao esquema atual.

Objetos incorporados não podem existir independentemente de um objeto pai. Ao alterar um objeto para um objeto incorporado, o bloco de migração deve garantir que cada objeto incorporado tenha exatamente um backlink para um objeto pai. Não ter backlinks ou ter vários backlinks gera as seguintes exceções:

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

Confira os exemplos de migração adicionais no repositório realm-swift.

Voltar

Tipos suportados