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

Threading - Swift SDK

Nesta página

  • Três regras a seguir
  • Executar uma escrita em background
  • Aguarde a conclusão das escritas assíncronas
  • Confirme ou cancele uma escrita assíncrona
  • Comunicação entre threads
  • Crie uma fila em série para usar o Realm em uma thread em background
  • Passe instâncias entre threads
  • Use o mesmo Realm em todos os threads
  • Atualização de Realms
  • Objetos congelados
  • Modelo de threading do Realm em detalhes
  • Comparação e contraste com Git
  • Estrutura interna
  • Resumo
  • Tipos Enviáveis, Não Enviáveis e Confinados a Threads

Para tornar seus aplicativos iOS e tvOS rápidos e responsivos, você deve equilibrar o tempo de computação necessário para organizar os visuais e lidar com interações do usuário com o tempo necessário para processar seus dados e executar sua lógica de negócios. Tipicamente, desenvolvedores de aplicativos distribuem esse trabalho em vários threads: o principal ou thread de UI para todo o trabalho relacionado à interface do usuário, e um ou mais threads de background para calcular volumes de trabalho mais pesados antes de enviá-los ao thread de UI para apresentação. Ao transferir trabalhos pesados para threads de background, o thread de UI pode permanecer altamente responsivo, independentemente do tamanho do volume de trabalho. Mas pode ser notoriamente difícil escrever um código multithread seguro, performático e sustentável que evite problemas como deadlocks e condições de corrida. O Realm visa simplificar isso para você.

Dica

Veja também:

A partir de 10.26.0, O Realm fornece métodos de gravação assíncrona para realizar gravações em background. Consulte: Executar uma gravação em background. Com a gravação assíncrona, você não precisa passar uma referência segura para threads ou objetos congelados entre os threads.

Esta página descreve como gerenciar manualmente os arquivos e objetos de Realm em todos os segmentos. O Realm também oferece suporte ao uso de um ator Swift para gerenciar o acesso ao Realm usando os recursos de simultaneidade do Swift . Para uma visão geral do suporte de atores do Realm, consulte Use Realm with Actors - Swift SDK.

Antes de explorar as ferramentas do Realm para aplicações de várias threads, entenda e siga estas três regras:

Não trave a leitura:
A arquitetura de controle de concorrência multiversão (MVCC) da Realm elimina a necessidade de bloqueio para operações de leitura. Os valores que você lê nunca serão corrompidos ou em um estado parcialmente modificado. Você pode ler livremente o mesmo arquivo Realm em qualquer thread sem a necessidade de bloqueios ou mutexes. O bloqueio desnecessário seria um gargalo de desempenho, pois cada thread poderia precisar esperar sua vez antes de ler.
Evite escritas síncronas na thread da UI se escrever em uma thread em background:
Você pode escrever em um arquivo Realm de qualquer thread, mas só pode haver um escritor por vez. Consequentemente, transações de escrita síncronas bloqueiam umas às outras. Uma escrita síncrona na thread da UI pode fazer com que seu aplicativo pareça não responsivo enquanto espera que uma escrita em uma thread de segundo plano seja concluída. O Device Sync escreve em uma thread de background, então você deve evitar escritas síncronas na thread da UI com realms sincronizados.
Não passe objetos ativos, coleções ou realms para outras threads:
Objetos ativos, collections e instâncias de Realm são confinados à thread: ou seja, são válidos somente na thread em que foram criados. De forma prática, isso significa que não é possível passar instâncias ativas para outras threads. No entanto, o Realm oferece vários mecanismos para compartilhar objetos entre threads.

Dica

Veja também:

Novidades na versão 10,26,0.

Você pode adicionar, modificar ou excluir objetos em segundo plano usando writeAsync.

Com writeAsync, você não precisa passar uma referência thread-safe ou objetos congelados entre threads. Em vez disso, chame realm.writeAsync. Você pode oferecer um bloco de conclusão para execução do método na thread de origem após a conclusão ou falha da escrita.

Itens a considerar nas escritas em background:

  • As escritas assíncronas bloqueiam o fechamento ou a invalidação do realm

  • Você pode confirmar ou cancelar transações explicitamente

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

O SDK fornece um Bool para sinalizar se o Realm está executando uma gravação assíncrona no momento. A variável isPerformingAsynchronousWriteOperations se torna true após uma chamada para um dos seguintes:

  • writeAsync

  • beginAsyncWrite

  • commitAsyncWrite

Permanece verdadeiro até que todas as operações de gravação assíncronas programadas sejam concluídas. Embora isso seja verdade, isso bloqueia o fechamento ou invalidação do domínio.

Para concluir uma escrita assíncrona, você ou o SDK devem chamar:

Quando você usa o método writeAsync, o SDK cuida da confirmação ou do cancelamento da transação. Isso fornece a conveniência da gravação assíncrona sem a necessidade de manter manualmente o estado vinculado ao escopo do objeto. No entanto, enquanto estiver no bloco writeAsync , você pode chamar explicitamente commitAsyncWrite ou cancelAsyncWrite. Se você retornar sem chamar um desses métodos, writeAsync :

  • Realiza a gravação após executar as instruções no bloco de gravação.

  • Retorna um erro

Em ambos os casos, isto conclui a operação writeAsync.

Para ter mais controle sobre quando confirmar ou cancelar a transação de gravação assíncrona, use o método beginAsyncWrite. Ao usar este método, você deve confirmar explicitamente as transações. Retornar sem confirmar uma gravação assíncrona cancela a transação. beginAsyncWrite retorna um ID que você pode passar para cancelAsyncWrite.

commitAsyncWrite confirma de forma assíncrona uma transação de gravação. Esta é a etapa que persiste os dados no domínio. commitAsyncWrite pode levar um bloco onComplete. Este bloco é executado no thread de origem quando o commit é concluído ou falha com um erro.

A chamada de commitAsyncWrite retorna imediatamente. Isso permite que o chamador continue enquanto o SDK executa a E/S em um thread em segundo plano. Esse método retorna um ID que você pode passar para cancelAsyncWrite. Isso cancela a invocação pendente do bloco de conclusão. Não cancela a confirmação em si.

Você pode agrupar chamadas sequenciais para commitAsyncWrite. O agrupamento dessas chamadas em lote melhora o desempenho de gravação; especialmente quando as transações em lote são pequenas. Para permitir o agrupamento de transações, configure o parâmetro isGroupingAllowed como true.

Você pode ligar para cancelAsyncWrite em beginAsyncWrite ou commitAsyncWrite. Quando você chama beginAsyncWrite, isso cancela toda a transação de escrita. Quando você o chama commitAsyncWrite, isso cancela apenas um bloco de onComplete que você pode ter passado para commitAsyncWrite. Não cancela a confirmação em si. Você precisa do ID do beginAsyncWrite ou do commitAsyncWrite que deseja cancelar.

Para acessar o mesmo arquivo Realm de diferentes threads, você deve instanciar uma instância de realm em cada thread que precisa de acesso. Desde que você especifique a mesma configuração, todas as instâncias de realm mapearão para o mesmo arquivo no disco.

Uma das principais regras para trabalhar com o Realm em um ambiente de várias threads é que os objetos são confinados pela thread: não é possível acessar as instâncias de um domínio, coleção ou objeto originado em outras threads. A arquitetura de Controle de concorrência multiversão (MVCC) do Realm significa que pode haver muitas versões ativas de um objeto a qualquer momento. O confinamento de threads garante que todas as instâncias nesse thread tenham a mesma versão interna.

Quando há necessidade de comunicação entre threads, você tem várias opções, dependendo do seu caso de uso:

  • Para modificar um objeto em dois threads, consulte o objeto em ambos os threads.

  • Para reagir às alterações feitas em qualquer thread, use as notificaçõesdo Realm's.

  • Para ver as mudanças que aconteceram em outro thread na instância de domínio do thread atual, atualize sua instância de domínio.

  • Para enviar uma visualização rápida e somente leitura do objeto para outros threads, "freeze" o objeto.

  • Para manter e compartilhar muitas visualizações somente para leitura do objeto em sua aplicação, copie o objeto de realm.

  • Para compartilhar uma instância de um domínio ou objeto específico com outro thread ou entre os limites do ator, compartilhe uma referência thread-safe para a instância do domínio ou objeto. Para obter mais informações, consulte Passar uma ThreadSafeReference.

Ao usar o Realm em uma conversa de fundo, crie uma fila de série. O Realm não é compatível com o uso de realms em filas simultâneas, como a fila global().

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

As instâncias de Realm, Results, Liste Objects gerenciadas são confinadas por thread. Isso significa que você só pode usá-las no tópico onde as criou. No entanto, o Realm fornece um mecanismo chamado referências thread-safe que permite copiar uma instância criada em um thread para outro thread.

Novidade na versão 10,20,0: @ThreadSafe wrapper e ThreadSafeReference estão em conformidade com Sendable

Se estiver a utilizar 5.6 o Swift ou superior, tanto o wrapper de propriedade @ThreadSafe como o ThreadSafeReference estão em conformidade com o Sendable.

Novidades na versão 10.17.0.

Você pode passar instâncias confinadas por thread para outra thread da seguinte maneira:

  1. Use o wrapper de propriedade @ThreadSafe para declarar uma variável que faça referência ao objeto original. Por definição, variáveis encapsuladas @ThreadSafe são sempre opcionais.

  2. Passe a variável encapsulada @ThreadSafe para a outra thread.

  3. Use a variável @ThreadSafe-wrapped como faria com qualquer outra opção. Se o objeto referenciado for removido do realm, a variável de referência se tornará 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"
}
}

Outra maneira de trabalhar com um objeto em outro thread é fazer uma query por ele novamente nesse thread. Mas se o objeto não tiver uma chave primária, não é trivial consultá-lo. Você pode usar o wrapper @ThreadSafe em qualquer objeto, independentemente de ele ter ou não uma chave primária.

Exemplo

O exemplo seguinte mostra como utilizar o @ThreadSafe em um parâmetro de função. Isso é útil para funções que podem ser executadas de forma assíncrona ou em outra thread.

Dica

Se a sua aplicação acessar Realm em um contexto do async/await, marque o código com @MainActor para evitar falhas relacionadas a threading.

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

Antes do Realm Swift SDK versão 10.17.0 ou no Objective-C, é possível passar instâncias confinadas por threads para outro thread da seguinte maneira:

  1. Inicializa um ThreadSafeReference com o objeto confinado à thread.

  2. Passe a referência para a outro thread ou fila.

  3. Resolva a referência no domínio do outro thread chamando Realm.resolve(_:). Use o objeto retornado normalmente.

Importante

Você deve resolver um ThreadSafeReference exatamente uma vez. Caso contrário, o domínio de origem permanece fixado até que a referência seja desalocada. Por essa razão, ThreadSafeReference deve ser de curta duração.

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

Outra maneira de trabalhar com um objeto em outro thread é fazer uma query por ele novamente nesse thread. Mas se o objeto não tiver uma chave primária, não é trivial consultá-lo. Você pode usar ThreadSafeReference em qualquer objeto, independentemente de ele ter ou não uma chave primária. Você também pode usá-lo com listas e resultados.

A desvantagem é que ThreadSafeReference requer algum código padrão. Lembre-se de encapsular tudo em um DispatchQueue com um autoreleaseFrequency adequadamente definido, para que os objetos não permaneçam no thread de background. Então, pode ser útil fazer uma extensão de conveniência para lidar com o código padrão da seguinte maneira:

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

Esta extensão adiciona um método writeAsync() à classe Realm. Esse método passa uma instância para um thread em background para você.

Exemplo

Suponha que você tenha feito um aplicativo de e-mail e queira excluir todos os e-mails lidos em background. Agora você pode fazer isso com duas linhas de código. Observe que o fechamento é executado no thread de background e recebe sua própria versão do domínio e do objeto passado:

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

Não é possível compartilhar instâncias de realm entre threads.

Para usar o mesmo arquivo domínio em todos os threads, abra uma instância de domínio diferente em cada thread. Contanto que você use a mesma configuração, todas as instâncias do domínio serão mapeadas para o mesmo arquivo no disco.

Quando você abre um realm, ele reflete a mais recente confirmação de gravação bem-sucedida e permanece nessa versão até ser atualizado. Isso significa que o realm não verá as mudanças que aconteceram em outro thread até a próxima atualização. Um realm no thread da UI -- mais precisamente, em qualquer thread de loop de eventos -- atualiza-se automaticamente no início do loop desse thread. No entanto, você deve atualizar manualmente as instâncias do realm que não existem em threads de loop ou que têm a atualização automática desativada.

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

Objetos vivos, confinados ao thread, funcionam bem na maioria dos casos. No entanto, alguns aplicativos -- aqueles baseados em arquiteturas reativas, baseadas em fluxo de eventos, por exemplo -- precisam enviar cópias imutáveis para vários threads para processamento antes de, finalmente, terminarem no thread da UI. Fazer uma cópia profunda toda vez seria caro, e o Realm não permite que instâncias vivas sejam compartilhadas entre threads. Nesse caso, você pode congelar e descongelar objetos, collections e realms.

O congelamento cria uma visão imutável de um objeto, collection ou domínio específico. O objeto, collection ou realm congelado ainda existe no disco e não precisa ser copiado profundamente quando passado para outros segmentos. Você pode compartilhar livremente o objeto congelado entre threads sem se preocupar com problemas de thread. Quando você congela um realm, seus objetos filhos também ficam congelados.

Dica

Use ThreadSafeReference com atores de Swift

Atualmente, o Realm não permite o uso de thaw() com Swift Actors. Para trabalhar com dados do Realm nos limites dos atores, utilize o ThreadSafeReference em vez de objetos congelados. Para mais informações, consulte Pass a ThreadSafeReference.

Objetos congelados não estão ativos e não são atualizados automaticamente. Eles são efetivamente snapshots do estado do objeto no momento do congelamento. Descongelar um objeto retorna uma versão ativa do objeto congelado.

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

Quando estiver trabalhando com objetos congelados, uma tentativa de realizar qualquer uma das seguintes ações gera uma exceção:

  • Abrir uma transação de gravação em um realm congelado.

  • Modificar um objeto congelado.

  • Adicionar um ouvinte de alteração a um realm, collection ou objeto congelado.

Você pode utilizar isFrozen para verificar se o objeto está congelado. Isso é sempre seguro para threads.

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

Objetos congelados continuam válidos desde que o domínio ativo que os gerou permaneça aberto. Portanto evite fechar o domínio ativo até que todas as threads tenham terminado com os objetos congelados. Você pode fechar um domínio congelado antes que o domínio ativo seja fechado.

Importante

Sobre o armazenamento em cache de objetos congelados

Armazenar muitos objetos congelados pode ter um impacto negativo no tamanho do arquivo do domínio. "Muitos" depende do dispositivo-alvo específico e do tamanho dos seus objetos domínio. Se você precisar armazenar em cache um grande número de versões, considere copiar o que você precisa fora do domínio.

Para modificar um objeto congelado, você deve descongelá-lo. Alternativamente, você pode consultar por ele em um reino não congelado e, então, modificá-lo. Chamar thaw em um objeto ativo, collection ou realm retorna a si mesmo.

Descongelar um objeto ou collection também descongela o realm a que ele faz referência.

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

Quando você adiciona a uma collection congelada, você deve descongelar tanto a collection quanto o objeto que deseja adicionar. Neste exemplo, consultamos dois objetos em um Realm congelado:

  • Um objeto Person que tem uma propriedade List de objetos Dog

  • Um objeto Dog

Devemos descongelar ambos os objetos antes de podermos adicionar o Dog à collection Lista de Dogs no Person. Se descongelarmos apenas o objeto Person, mas não o Dog, o Realm lançará um erro.

A mesma regra se aplica ao passar objetos congelados entre threads. Um caso comum pode ser chamar uma função em um thread em background para fazer algum trabalho em vez de bloquear a interface do usuário.

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

O Realm fornece acesso seguro, rápido, sem bloqueios e simultâneo em todos os threads com seu MVCC (Multiversion Concurrency Control) arquitetura.

Se você está familiarizado com um sistema de controle de versão distribuído como o Git, talvez já tenha uma compreensão intuitiva do MVCC. Dois elementos fundamentais do Git são:

  • Confirmações, que são escritas atômicas.

  • Ramificações, que são versões diferentes do histórico de confirmações.

Da mesma forma, o Realm tem gravações confirmadas atomicamente na forma de transações. O Realm também tem muitas versões diferentes da história a qualquer momento, como ramificações.

Ao contrário do Git, que suporta ativamente a distribuição e a divergência por meio de forking, um realm só tem uma versão mais recente verdadeira em um determinado momento e sempre escreve para o head dessa versão mais recente. O Realm não pode escrever em uma versão anterior. Isso significa que seus dados convergem para uma versão mais recente da verdade.

Um domínio é implementado usando uma estrutura de dados B+tree.. O nó de alto nível representa uma versão do domínio; nós secundários são objetos nessa versão do domínio. O domínio tem um ponteiro para sua versão mais recente, assim como o Git tem um ponteiro para sua confirmação de CABEÇALHO.

O Realm usa uma técnica de cópia em gravação para garantir isolamento e durabilidade. Quando você faz alterações, o Realm copia a parte relevante da árvore para gravar. Em seguida, Realm confirma as alterações em duas fases:

  • O Realm escreve as alterações no disco e verifica se foi feito.

  • Em seguida, o Realm coloca o ponteiro da versão mais recente apontando para a versão recém-escrita.

Esse processo de confirmação em duas etapas garante que, mesmo que a gravação falhe parcialmente, a versão original não será corrompida de forma alguma, pois as alterações foram feitas em uma cópia da parte relevante da árvore. Da mesma forma, o ponteiro raiz do domínio apontará para a versão original até que a nova versão seja válida.

Exemplo

O diagrama a seguir ilustra o processo de confirmação:

O Realm copia a parte relevante da árvore para gravações e, em seguida, substitui a versão mais recente atualizando um ponteiro.
clique para ampliar
  1. O realm é estruturado como uma árvore. O realm tem um ponteiro para a sua última versão, V1.

  2. Ao escrever, o Realm cria uma nova versão V2 com base na V1. Realm faz cópias de objetos para modificação (A 1 , C 1), enquanto links para objetos não modificados continuam a apontar para as versões originais (B, D).

  3. Após validar o commit, o Realm atualiza o ponteiro para a nova versão mais recente, V2. O Realm então descarta nós antigos que não estão mais conectados à árvore.

Realm usa técnicas de cópia zero, como mapeamento de memória, para lidar com dados. Quando você lê um valor do realm, você está virtualmente olhando para o valor no disco real, não uma cópia dele. Esta é a base para objetos vivos. É também por isso que um ponteiro de head de realm pode ser definido para apontar para a nova versão depois que a gravação no disco tiver sido validada.

  • O Realm habilita a programação simples e segura de várias threads seguindo três regras:

    • não travar para ler

    • evite gravações no thread da IU se você gravar em threads em segundo plano ou usar o Device Sync

    • não passar objetos ativos para outras threads.

  • Há uma maneira adequada de compartilhar objetos entre threads para cada caso de uso.

  • Para ver as alterações feitas em outras threads na sua instância de realm,atualize manualmente as instâncias de realm que não existem nas threads de "loop" ou cuja atualização automática esteja desativada.

  • Para aplicativos baseados em arquiteturas reativas e em fluxo de eventos, você pode congelar objetos, collections e realms para passar cópias superficiais de forma eficiente para diferentes threads para processamento.

  • A arquitetura de controle de concorrência multiversão (MVCC) do Realm é semelhante à do Git. Diferentemente do Git, o Realm possui apenas uma única versão mais recente para cada realm.

  • O Realm faz confirmações em duas etapas para garantir o isolamento e a durabilidade.

A API pública do SDK do Realm Swift contém tipos que se enquadram em três categorias amplas:

  • Enviável

  • Não pode ser enviado e não está confinado a threads

  • Confinado por thread

Você pode compartilhar tipos que não são Sendable e que não são confinados por thread entre threads, mas deve sincronizá-los.

Os tipos confinados por thread, a menos que congelados, estão confinados a um contexto de isolamento. Você não pode passá-los entre esses contextos, mesmo com sincronização.

Enviável
Non-Sendable
Confinada à thread
AnyBSON
RLMAppConfiguration
AnyRealmCollection
AsyncOpen
RLMFindOneAndModifyOptions
AnyRealmValue
AsyncOpenSubscription
RLMFindOptions
Lista
RLMAPIKeyAuth
RLMNetworkTransport
Map
RLMApp
RLMRequest
MutableSet
RLMAsyncOpenTask
RLMResponse
Projeção
RLMChangeStream
RLMSyncConfiguration
RLMArray
RLMCompensatingWriteInfo
RLMSyncTimeoutOptions
RLMChangeStream
RLMCredentials
RLMDictionary
RLMDecimal128
RLMDictionaryChange
RLMEmailPasswordAuth
RLMEmbeddedObject
RLMMaxKey
RLMLinkingObjects
RLM Minkey
Objeto RLM
Cliente RLMMongoClient
RLMPropertyChange
RLMMongoCollection
RLMRealm
RLMMongoDatabase
RLMResults
RLMObjectId
RLMSection
RLMObjectSchema
RLMMongoClient
RLMProgressNotification
RLMSectionedResultsChangeset
RLMProgressNotificationToken
RLMSet
RLMProperty
RLMSyncSubscription
RLMPropertyDescriptor
RLMSyncSubscriptionSet
RLMProviderClient
RealmOptional
RLMPushClient
RealmProperty
RLMSchema
RLMSortDescriptor
RLMSyncErrorActionToken
RLMSyncManager
RLMSyncSession
RLMThreadSafeReference
RLMUpdateResult
RLMUser
RLMUserAPIKey
RLMUserIdentity
RLMUserProfile
ThreadSafe

Voltar

Excluir