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
- Introdução
- Installing Dependencies
- The Model
- Implementing Realm
- Conclusion
Sem mais delongas, vamos dar uma olhada na aplicação que vamos construir nesta série…
Introdução
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:
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:
- Criando o objeto Realm
- Bridging between our Realm object and our primitive Note object
- 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.