Si vous préférez les vidéos aux articles écrits, cet article est une version écrite d’une vidéo que j’ai produite. Le contenu est identique.
Cette vidéo est la première d’une série qui, je l’espère, servira à vous apprendre à utiliser les frameworks et outils iOS tels que les raccourcis Siri, CloudKit, et plus encore. Si vous avez un framework ou une fonctionnalité spécifique que vous aimeriez voir couvrir par cette série, n’hésitez pas à m’écrire à jordanosterbergshadowsystemstech, ou sur Twitter @josterbe1.
Table des matières
- Introduction
- Installation des dépendances
- Le modèle
- Implémentation de Realm
- Conclusion
Sans plus attendre, jetons un coup d’œil à l’application que nous allons construire dans cette série….
Introduction
Nous avons notre liste de notes, et lorsque nous tapons sur l’une d’entre elles, nous pouvons la lire et commencer à l’éditer, ou la supprimer. C’est assez simple. Vous remarquerez, si vous téléchargez le projet de démarrage, que les notes ne persistent pas lorsque vous entrez et sortez du NoteDetailController en tapant sur la note « Apple Park Visit ». C’est-à-dire que le contenu de la note ne s’enregistre pas lorsque vous la modifiez.
C’est ce que nous allons construire dans cet article, en utilisant la base de données Realm. J’utilise Realm depuis à peu près deux ans, et je trouve que sa simplicité l’emporte sur le coût de l’utilisation d’une bibliothèque tierce. En fait, je l’utilise dans l’application sur laquelle je passe la plupart de mon temps de développement personnel (voir https://countdowns.download) sur macOS et iOS.
Installation des dépendances
Pour commencer à utiliser Realm, nous devons l’installer en utilisant CocoaPods. CocoaPods, si vous ne le savez pas, CocoaPods est un outil de gestion des dépendances qui est largement utilisé dans l’espace iOS. Si vous n’avez pas déjà installé CocoaPods sur votre Mac, vous pouvez utiliser la commande sudo gem install cocoapods
pour commencer. Maintenant, ouvrez le dossier du projet, ainsi qu’une fenêtre Terminal à l’intérieur de ce répertoire.
Tapez pod init
, puis open Podfile
.
À l’intérieur du « Podfile » nouvellement créé, nous devons écrire un texte qui informera CocoaPods des bibliothèques que vous souhaitez installer dans votre projet.
Au-dessous de # Pods for NotesApp
, écrivez ces deux lignes :
pod 'Realm', '~> 3.12.0'pod 'RealmSwift', '~> 3.12.0'
Votre Podfile devrait ressembler à ceci après avoir écrit ces lignes :
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
Maintenant que nous avons ajouté nos dépendances, demandons à CocoaPods de les installer avec pod install
Cela prendra un certain temps lorsque vous utiliserez CocoaPods pour la première fois. Ne vous inquiétez pas, CocoaPods est juste en train de télécharger quelques composants initiaux. Cela ne se produira pas chaque fois que vous pod install
.
Votre fenêtre de terminal ressemblera à ceci une fois que cette commande aura fini de s’exécuter :
Après cela, si vous avez déjà ouvert le NotesApp.xcodeproj
, fermez-le. Lorsque vous utilisez CocoaPods, vous devez utiliser le fichier .xcworkspace
au lieu du fichier .xcodeproj
par défaut. Ouvrez le fichier NotesApp.xcworkspace
et dirigez-vous vers Note.swift
.
Le modèle
Cette classe contient notre objet modèle Note, qui contient quelques propriétés de base :
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 }}
Code standard du modèle, rien de spécial ne se passe ici.
Nous avons également une extension à notre objet Note dans le même fichier, qui se sous-classe en tant que protocole appelé Writeable
extension Note: Writable { func write(dataSource: DataSource) { self.lastEdited = Date() dataSource.store(object: self) } func delete(dataSource: DataSource) { dataSource.delete(object: self) }}
À l’intérieur des fonctions write
et delete
, vous remarquerez que nous avons une propriété DataSource
. DataSource
est un protocole générique pour aider à rendre la modification des données aussi abstraite que possible aux niveaux supérieurs de notre code.
Voici la définition du protocole :
protocol DataSource { func store<T>(object: T) func delete<T>(object: T)}
Si vous n’êtes pas familier avec les génériques, chacune de nos fonctions a un paramètre T
qui signifie essentiellement qu’il peut être n’importe quel type d’objet. Ce n’est pas très utilisé dans notre projet, mais il pourrait être évolué et utilisé plus loin pour créer plusieurs DataSources avec différentes contraintes autour des objets qu’ils peuvent stocker.
Nous mettons en œuvre notre protocole DataSource
dans NoteDataSource
. Il n’y a rien de spécial ici non plus, à part un petit détail que j’aimerais noter pour l’explication.
Chaque fois que nous store
ou delete
objets, nous utilisons l’appel suivant à 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")}
Essentiellement, chaque fois qu’une note est stockée ou supprimée, nous informons les auditeurs que nos données ont changé, afin qu’ils puissent mettre à jour leur interface utilisateur en conséquence.
Avec tous nos fichiers de modèle et nos classes hors du chemin, commençons à implémenter Realm !
Mise en œuvre de Realm
Il y a trois étapes pour intégrer Realm à notre projet :
- Création de l’objet Realm
- Pontage entre notre objet Realm et notre objet primitif Note
- Commencer à récupérer et modifier les données avec Realm
Création de l’objet Realm
Cette étape est relativement simple. Créons un nouveau fichier Swift appelé RealmNote.swift
. A l’intérieur de RealmNote.swift
, importez le framework RealmSwift et créez une déclaration de classe comme suit :
import RealmSwiftclass RealmNote: Object {}
Nous allons sous-classer la classe Object
de Realm qui nous permettra d’utiliser RealmNote
dans les fonctions de la base de données Realm.
Maintenant, ajoutez les trois propriétés que nous avons dans notre modèle Note:
@objc dynamic var identifier: String = ""@objc dynamic var content: String = ""@objc dynamic var lastEdited: Date = Date()
Les morceaux @objc dynamic
de notre déclaration de variable exposent nos propriétés à l’Objective-C, dans lequel de nombreuses couches iOS de Realm sont écrites. Cela permet également à Realm d’écouter les changements apportés à nos objets RealmNote
.
Pour terminer notre classe, surchargez la class func
primaryKey, qui renvoie une chaîne optionnelle (String?
) avec la valeur « identifiant ». Cela informe Realm que la clé primaire de RealmNote
, une façon d’identifier de façon unique nos objets, est stockée dans la propriété « identifier ».
Une fois que vous avez terminé ces étapes, votre RealmNote
ressemblera à ceci:
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" }}
C’est tout pour la première étape.
Pont entre notre objet Realm et notre objet Note primitif
Nous avons deux objets modèles séparés : Note
et RealmNote
. RealmNote est utilisé en interne lors du traitement de Realm, afin de garder notre couche de modèle découplée de notre interface utilisateur. En utilisant deux objets séparés, nous pourrions nous passer de l’utilisation de Realm à l’avenir si le besoin s’en fait sentir.
Dans le fichier RealmNote.swift
, créez une extension de RealmNote
:
extension RealmNote {}
Maintenant, créez un convenience init
à l’intérieur de l’extension qui prend un Note
comme seule propriété. Cela nous permettra de créer des objets RealmNote
en utilisant un objet Note
.
convenience init(note: Note) { self.init() self.identifier = note.identifier self.content = note.content self.lastEdited = note.lastEdited}
Génial, maintenant, pour terminer RealmNote.swift
, créez une variable Note
à l’intérieur de l’extension qui s’initialise à partir d’un RealmNote
:
var note: Note { return Note(realmNote: self)}
Ne vous inquiétez pas si Xcode vous donne une erreur à propos de l’initialisateur de Note, nous allons corriger cela.
Passez à Note.swift
, où nous sommes sur le point d’écrire l’autre moitié de notre pont. Ce code est essentiellement la même chose que l’extension 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) }}
Génial, c’est la deuxième étape. Nous pouvons maintenant accéder à un RealmNote
depuis un Note
, et à un Note
depuis un RealmNote
. Cela signifie également que ce code est parfaitement valide :
Note(content: "Example").realmNote.note.realmNote.note.realmNote.note.realmNote// and so on...
Parenthèse de plaisanterie, terminons notre application par l’étape trois.
Commencez à récupérer et à modifier des données avec Realm
Partez dans NoteDataSource.swift
, et import RealmSwift
avant la déclaration de classe. Avant de modifier, supprimer et récupérer des objets Realm, nous avons besoin d’une instance de la base de données Realm. Remplacez le init de NoteDataSource
par ceci:
var realm: Realminit() { // Load our data self.realm = try! Realm()}
Cela créera une instance de la base de données Realm. En production, vous ne voudriez probablement pas utiliser l’opérateur bang ( !) lors de la création de l’instance car votre application se plantera si la base de données n’est pas disponible.
Puis, éditons la fonction store
pour stocker réellement des objets dans notre base de données.
Écrire avec Realm est simple:
try? self.realm.write {}
À l’intérieur de ce bloc de code, nous pouvons mettre à jour les objets dans la base de données. Ecrivez ceci:
self.realm.add(note.realmNote, update: true)
Cela va soit créer un nouveau RealmNote
dans la base de données, soit mettre à jour un RealmNote
existant s’il existe. C’est tout ! Nous stockons maintenant des objets dans la base de données Realm (la fonction d’écriture de la note d’appel est effectuée dans NoteDetailController.swift
si vous souhaitez voir la fonction qui est réellement utilisée pour effectuer cette écriture.)
Maintenant, écrivons notre fonction delete
. En raison de la façon dont nous avons écrit notre pont (sans consulter Realm chaque fois que nous créons un RealmNote
à partir d’un Note
), nous devons aller chercher l’objet directement dans la base de données en utilisant l’identifiant de la note plutôt qu’en utilisant sa propriété realmNote
.
C’est simple:
if let realmNote = self.realm.object(ofType: RealmNote.self, forPrimaryKey: note.identifier) {}
Cela demande à Realm de récupérer un objet RealmNote
de la base de données, avec l’identifiant, ou clé primaire, de note.identifier
.
Cela peut être un peu funky. Pour une raison quelconque, l’application se plante si nous utilisons la fonction traditionnelle write
sur Realm. Comme solution de rechange, ce code est parfaitement valide et effectue essentiellement la même tâche que write
:
self.realm.beginWrite()self.realm.delete(realmNote)try? self.realm.commitWrite()
Nous commençons notre écriture, nous supprimons l’objet et nous validons notre écriture.
Avec cela, nous avons construit une application de note fonctionnelle!
Conclusion
J’espère que vous avez apprécié ce tutoriel sur la façon d’utiliser la base de données Realm. J’ai eu beaucoup de plaisir à le réaliser et j’ai hâte de faire évoluer cette série et d’ajouter d’autres fonctionnalités à notre application au fil du temps, comme les raccourcis Siri, CloudKit, et plus encore. Merci de votre lecture.