Realm Database Guide – Building a Note app in Swift para iOS

Se preferir vídeos em vez de artigos escritos, este artigo é uma versão escrita de um vídeo que eu produzi. O conteúdo é idêntico.

Este vídeo é o primeiro de uma série que espero que sirva para lhe ensinar como usar frameworks e ferramentas iOS como o Siri Shortcuts, CloudKit, e muito mais. Se você tem um framework ou recurso específico que você gostaria de ver a capa desta série, sinta-se à vontade para me escrever no jordanosterbergshadowsystemstech, ou no Twitter @josterbe1.

Índice

  1. Introdução
  2. Installing Dependencies
  3. The Model
  4. Implementing Realm
  5. Conclusion

Sem mais delongas, vamos dar uma olhada na aplicação que vamos construir nesta série…

Introdução

A lista de notas da aplicação
Editando uma nota individualmente

Temos a nossa lista de notas, e quando tocamos numa, podemos ler e começar a editá-la, ou apagá-la. Bastante simples. Se fizer o download do projecto inicial, notará que as notas não persistem quando entra e sai do NoteDetailController quando toca na nota “Apple Park Visit”. Ou seja, o conteúdo da nota não salva quando você a edita.

É isso que vamos construir neste artigo, usando a Base de Dados Realm. Eu uso o Realm há apenas dois anos, e acho que sua simplicidade compensa o custo de usar uma biblioteca de terceiros. Na verdade, eu a uso no aplicativo em que gasto a maior parte do meu tempo de desenvolvimento pessoal (veja https://countdowns.download) tanto em macOS quanto em iOS.

Instalando Dependências

Para começar a usar o Realm, precisamos instalá-lo usando CocoaPods. CocoaPods, se você não está ciente, CocoaPods é uma ferramenta de gestão de dependências que é amplamente utilizada no espaço iOS. Se você ainda não tem CocoaPods instalado no seu Mac, você pode usar o comando sudo gem install cocoapods para começar a usar. Agora, abra a pasta do projeto, assim como uma janela de Terminal dentro desse diretório.

Digite pod init, e depois open Podfile.

Dentro do recém-criado “Podfile”, precisamos escrever algum texto que informará ao CocoaPods quais bibliotecas você gostaria de instalar no seu projeto.

Below # Pods for NotesApp, escreva estas duas linhas:

pod 'Realm', '~> 3.12.0'pod 'RealmSwift', '~> 3.12.0'

Seu Podfile deve ficar parecido com isto depois de ter escrito essas linhas:

platform :ios, '12.0'target 'NotesApp' do use_frameworks! # Pods for NotesApp pod 'Realm', '~> 3.12.0' pod 'RealmSwift', '~> 3.12.0' target 'NotesAppTests' do inherit! :search_paths end target 'NotesAppUITests' do inherit! :search_paths endend

Agora adicionamos as nossas dependências, vamos pedir ao CocoaPods para as instalar com pod install

Isto vai demorar algum tempo quando você usar CocoaPods pela primeira vez. Não se preocupe, CocoaPods está apenas baixando alguns componentes iniciais. Isto não acontecerá toda vez que você pod install.

A sua janela de Terminal ficará assim uma vez que esse comando terminar de executar:

Janela Terminal

Após isto, se você já tiver aberto o NotesApp.xcodeproj, feche fora dele. Ao usar CocoaPods, você deve usar o arquivo .xcworkspace ao invés do arquivo padrão .xcodeproj. Abra o ficheiro NotesApp.xcworkspace e vá para Note.swift.

O Modelo

Esta classe contém o nosso objecto modelo Nota, que contém algumas propriedades básicas:

class Note { var identifier: String var content: String var lastEdited: Date init( identifier: String = UUID().uuidString, content: String, lastEdited: Date = Date()) { self.identifier = identifier self.content = content self.lastEdited = lastEdited }}

Código do modelo padrão, nada de especial se passa aqui.

Temos também uma extensão para o nosso objecto Nota no mesmo ficheiro, que subclasses como protocolo chamado Writeable

extension Note: Writable { func write(dataSource: DataSource) { self.lastEdited = Date() dataSource.store(object: self) } func delete(dataSource: DataSource) { dataSource.delete(object: self) }}

Inside of the write and delete functions, you’ll notice we have a DataSource property. DataSource é um protocolo genérico para ajudar a modificar dados o mais abstrato possível nos níveis mais altos do nosso código.

Aqui está a definição do protocolo:

protocol DataSource { func store<T>(object: T) func delete<T>(object: T)}

Se você não está familiarizado com genéricos, cada uma de nossas funções tem um parâmetro T o que significa essencialmente que pode ser qualquer tipo de objeto. Isso não é muito usado em nosso projeto, mas pode ser evoluído e usado para criar múltiplas Fontes de Dados com diferentes restrições em torno dos objetos que eles podem armazenar.

Implementamos nosso protocolo DataSource em NoteDataSource. Também não há nada de especial aqui, além de um pequeno tidbit que eu gostaria de anotar para explicar.

Quando nós store ou delete objetos, nós usamos a seguinte chamada para NotificationCenter:

NotificationCenter.default.post(name: .noteDataChanged, object: nil)// We also have this extension of Notification.Name to make sending and receiving this notification simple.extension Notification.Name { static let noteDataChanged = Notification.Name(rawValue: "noteDataChanged")}

Essencialmente, sempre que qualquer nota é armazenada ou excluída, nós informamos a qualquer ouvinte que nossos dados foram alterados, para que eles possam atualizar sua IU de acordo.

Com todos os nossos arquivos de modelo e classes fora do caminho, vamos começar a implementar o Realm!

Implementando o Realm

Existem três passos para integrar o Realm ao nosso projeto:

  1. Criando o objeto Realm
  2. Bridging between our Realm object and our primitive Note object
  3. Begin retrieving and modifying data with Realm

Criando o objeto Realm

Este passo é relativamente simples. Vamos criar um novo arquivo Swift chamado RealmNote.swift. Dentro de RealmNote.swift, importe o framework RealmSwift e crie uma declaração de classe assim:

import RealmSwiftclass RealmNote: Object {}

Vamos subclassificar a classe Realm Object que nos permitirá usar RealmNote em funções de banco de dados Realm.

Agora, adicione nas três propriedades que temos no nosso modelo Nota:

@objc dynamic var identifier: String = ""@objc dynamic var content: String = ""@objc dynamic var lastEdited: Date = Date()

As @objc dynamic peças da nossa declaração de variáveis expõem as nossas propriedades ao Objective-C, no qual muitas das camadas iOS do Realm estão escritas. Ele também permite que Realm escute as alterações dos nossos RealmNote objetos.

Para terminar a nossa classe, substitua a class func primaryKey, que retorna uma string opcional (String?) com o valor “identificador”. Isto informa a Realm que a chave primária de RealmNote, uma forma de identificar exclusivamente nossos objetos, é armazenada na propriedade “identificador”.

Após ter completado estes passos, seu RealmNote será parecido com isto:

class RealmNote: Object { @objc dynamic var identifier: String = "" @objc dynamic var content: String = "" @objc dynamic var lastEdited: Date = Date() override class func primaryKey() -> String? { return "identifier" }}

É tudo para o primeiro passo.

Ponte entre nosso objeto Realm e nosso objeto primitivo Note

Temos dois objetos modelo separados: Note e RealmNote. RealmNote é usado internamente quando lidamos com RealmNote, a fim de manter nossa camada de modelo desacoplada da nossa IU. Usando dois objetos separados, podemos mudar de usar o Realm no futuro se a necessidade for suprida.

No arquivo RealmNote.swift, crie uma extensão de RealmNote:

extension RealmNote {}

Agora, crie um convenience init dentro da extensão que leva um Note como sua única propriedade. Isto permitir-nos-á criar objectos RealmNote usando um objecto Note.

convenience init(note: Note) { self.init() self.identifier = note.identifier self.content = note.content self.lastEdited = note.lastEdited}

Great, now, to finish RealmNote.swift off, create a Note variable inside the extension which initializes from a RealmNote:

var note: Note { return Note(realmNote: self)}

Não se preocupe se o Xcode lhe der um erro sobre o inicializador do Note, estamos prestes a corrigir isso.

Cabeça até Note.swift, onde estamos prestes a escrever a outra metade da nossa ponte. Este código é essencialmente a mesma coisa que a extensão de RealmNote.

extension Note { convenience init(realmNote: RealmNote) { self.init(identifier: realmNote.identifier, content: realmNote.content, lastEdited: realmNote.lastEdited) } var realmNote: RealmNote { return RealmNote(note: self) }}

Great, esse é o segundo passo. Agora podemos acessar um RealmNote a partir de um Note, e um Note a partir de um RealmNote. Isto também significa que este código é perfeitamente válido:

Note(content: "Example").realmNote.note.realmNote.note.realmNote.note.realmNote// and so on...

Jokes à parte, vamos terminar nossa aplicação com o passo três.

Inicie a recuperação e modificação de dados com Realm

Cabeça em NoteDataSource.swift, e import RealmSwift antes da declaração de classe. Antes de modificar, apagar e recuperar objetos Realm, precisamos de uma instância da base de dados Realm. Substitua NoteDataSource‘s init por isto:

var realm: Realminit() { // Load our data self.realm = try! Realm()}

Isto irá criar uma instância do banco de dados Realm. Em produção, você provavelmente não vai querer usar o operador bang (!) ao criar a instância porque sua aplicação irá travar se o banco de dados não estiver disponível.

Próximo, vamos editar a função store para realmente armazenar objetos em nosso banco de dados.

Escrever com Realm é simples:

try? self.realm.write {}

Dentro desse bloco de código, podemos atualizar objetos dentro do banco de dados. Escreva isto:

self.realm.add(note.realmNote, update: true)

Isto irá criar um novo RealmNote na base de dados ou actualizar um já existente, se existir. É isso mesmo! Estamos agora a armazenar objectos na base de dados Realm (a função de escrita da nota é executada em NoteDetailController.swift se quiser ver a função que é realmente utilizada para executar esta escrita)

Agora, vamos escrever a nossa função delete. Devido à forma como escrevemos a nossa ponte (sem consultar Realm sempre que criamos um RealmNote a partir de um Note), temos de ir buscar o objecto directamente à base de dados usando o identificador da nota em vez de usar a sua propriedade realmNote.

É simples:

if let realmNote = self.realm.object(ofType: RealmNote.self, forPrimaryKey: note.identifier) {}

Pede à Realm que recupere um objecto RealmNote da base de dados, com o identificador, ou chave primária, de note.identifier.

Pode ser um pouco funky. Por algum motivo, a aplicação trava se usarmos a função tradicional write no Realm. Como alternativa, este código é perfeitamente válido e executa essencialmente a mesma tarefa de write:

self.realm.beginWrite()self.realm.delete(realmNote)try? self.realm.commitWrite()

Começamos a nossa escrita, apagamos o objecto e submetemos a nossa escrita.

Com isso, construímos uma aplicação de notas funcional!

Conclusão

Espero que tenha gostado deste tutorial sobre como usar a Base de Dados Realm. Eu me diverti muito fazendo isso e mal posso esperar para evoluir esta série e adicionar mais funcionalidades à nossa aplicação ao longo do tempo, tais como Siri Shortcuts, CloudKit, e muito mais. Obrigado por ler.

Deixe uma resposta

O seu endereço de email não será publicado.