Tutoriel Realm with SwiftUI: Premiers pas

Online Coding Courses for Kids

Base de données mobile du royaume est un système de gestion de base de données d’objets populaire. Il est open source et peut être utilisé sur plusieurs plates-formes. Realm vise à être une solution rapide, performante, flexible et simple pour les données persistantes, tout en continuant à écrire du code Swift sécurisé.

SwiftUI est la dernière et la plus chaude infrastructure d’interface utilisateur d’Apple. Il utilise une syntaxe déclarative pour créer vos vues à l’aide du code Swift. Il repose sur États pour mettre à jour de manière réactive ses vues lorsque l’utilisateur interagit avec lui. Depuis que Realm utilise Objets vivants qui se mettent également à jour automatiquement, mélanger les deux frameworks a du sens!

Dans ce didacticiel SwiftUI Realm, vous apprendrez à:

  • Configurer le royaume
  • Définir des modèles de données
  • Effectuer des opérations CRUD de base sur des objets
  • Propager les modifications de la base de données vers l’interface utilisateur
  • Gérez les migrations lorsque votre modèle de données change

Vous apprendrez tout cela en implémentant une base de données Realm dans une application qui garde une trace de tous les ingrédients dont vous avez besoin pour créer potions magiques! Alors prenez votre kit de potions, car il est temps de plonger directement dans ce chaudron. :]

Commencer

Téléchargez les documents du projet à l’aide du Télécharger les matériaux bouton en haut ou en bas de ce didacticiel. Ouvert PotionsMaster.xcodeproj à l’intérieur de entrée dossier.

PotionsMaître est une application conçue pour tous vos besoins en matière de fabrication de potions. Le brassage de potions est une compétence difficile. Les techniques d’agitation, le timing et la mise en bouteille peuvent être des tâches ardues, même pour des magiciens expérimentés. Cette application vous aide à suivre les ingrédients dont vous avez besoin et ceux que vous avez déjà achetés. Avec PotionsMaster, même cette nouvelle potion difficile que vous avez lu sera un jeu d’enfant!

Il est maintenant temps de se mettre au travail. Pour démarrer, construire et exécuter.

SwiftUI Realm: Liste des ingrédients et ingrédients achetés

PotionsMaster est une application simple qui vous permet d’ajouter, de mettre à jour et de supprimer des ingrédients dans une liste. Mais en jouant avec l’application, vous remarquerez un petit problème. Peu importe ce que vous faites, l’application ne conserve pas vos données! En fait, il ne fonctionne pas tout actions lorsque vous essayez de créer, mettre à jour ou supprimer un ingrédient. Mais ne vous inquiétez pas, vous êtes sur le point de le faire fonctionner, en utilisant Realm.

Structure du projet

Avant de plonger et de réparer l’application pour pouvoir commencer à préparer votre prochaine potion, examinez de près le projet de démarrage. Il contient les fichiers clés suivants:

  • Ingrédient.swift: Cette structure est une représentation d’un ingrédient.
  • IngredientStore.swift: Il s’agit d’une implémentation de classe du modèle de magasin. Cette classe gère le stockage des ingrédients. C’est également là que vous exécuterez des actions sur ces ingrédients.
  • IngredientListView.swift: Ceci est la vue principale de l’application. Cette classe affiche un List. Il y en a un Section pour les ingrédients à acheter, et un autre pour les ingrédients achetés.
  • IngredientFormView.swift: Vous utiliserez ceci Form pour créer et mettre à jour des ingrédients.

Le projet utilise le Modèle de magasin pour gérer les états et propager les modifications dans l’interface utilisateur. IngredientStore a une liste d’ingrédients, ceux que vous devez acheter et ceux que vous avez déjà achetés. Lorsque l’utilisateur interagit avec l’application, une action modifie l’état. Ensuite, SwiftUI reçoit un signal pour mettre à jour l’interface utilisateur avec le nouvel état.

Travailler avec Realm

Realm a été conçu pour résoudre les problèmes courants des applications actuelles. Il fournit de nombreuses solutions élégantes et faciles à utiliser. Et il est disponible pour plusieurs plates-formes, y compris, mais sans s’y limiter:

  • Swift / Objective-C
  • Java / Kotlin
  • JavaScript
  • .NET

La partie la plus cool de Realm est que les compétences sont transférables. Une fois que vous avez appris les bases de Realm dans une langue, il est facile de les apprendre dans une autre langue. Et comme Realm est une base de données multiplateforme, ses API ne changent pas beaucoup d’une langue à l’autre.

Pourtant, Realm n’est pas une base de données polyvalente. Contrairement à SQLite, Realm est un NoSQL base de données d’objets. Comme toute autre base de données NoSQL, elle présente des avantages et des inconvénients. Mais Realm est une excellente alternative pour synchroniser les équipes multi-plateformes.

Comprendre la base de données du royaume

Avant de commencer à configurer Realm, vous devez comprendre un peu son fonctionnement.

Utilisations du royaume des dossiers pour sauvegarder et gérer votre base de données. Chaque base de données Realm de votre application est appelée domaine. Votre application peut avoir plusieurs domaines, chacun gérant un domaine d’objets différent. Cela permet de garder votre base de données organisée et concise dans votre application. Et comme il est disponible sur toutes les plates-formes, vous pouvez partager des fichiers Realm préchargés entre des plates-formes comme iOS et Android. C’est vraiment utile, non? :]

Pour ouvrir un fichier Realm, il vous suffit d’instancier un nouveau Realm objet. Si vous ne transmettez pas de chemin de fichier personnalisé, Realm crée un default.realm fichier dans le Des documents dossier sur iOS.

Parfois, vous souhaiterez peut-être utiliser un domaine sans réellement écrire de données sur le disque. La base de données fournit une solution pratique pour ces situations: royaumes en mémoire. Ceux-ci peuvent être utiles lors de l’écriture de tests unitaires. Vous pouvez utiliser des domaines en mémoire pour précharger, modifier et supprimer des données pour chaque scénario de test sans réellement écrire sur le disque.

Realm Mobile Database n’est pas le seul produit fourni par Realm. L’entreprise propose également Synchronisation du royaume, une solution pour synchroniser les bases de données Realm sur plusieurs appareils et dans le cloud. De plus, Realm fournit une excellente application pour ouvrir, modifier et gérer vos bases de données: Realm Studio.

Configurer le royaume

Pour commencer à utiliser Realm, vous devez l’inclure en tant que dépendance dans votre projet. Il existe de nombreux outils de gestion des dépendances que vous pouvez utiliser pour cela, tels que Gestionnaire de packages Swift et CocoaPods. Ce didacticiel utilise Swift Package Manager, mais n’hésitez pas à utiliser l’outil avec lequel vous êtes plus à l’aise.

Pour configurer votre dépendance, sélectionnez Fichier ▸ Paquets Swift ▸ Ajouter une dépendance de paquet…. Copiez ce qui suit et collez-le dans la zone de recherche / saisie combinée:

https://github.com/realm/realm-cocoa.git

Il s’agit de l’emplacement du référentiel GitHub contenant le package Realm. Cliquez sur Suivant.

Fenêtre Xcode avec une recherche / entrée pour taper l'emplacement de la dépendance

Ensuite, Xcode vous demande de définir certaines options pour ce package. Laissez simplement la valeur par défaut de Jusqu’au prochain majeur pour utiliser la dernière version de Realm. (Au moment d’écrire ces lignes, il s’agit donc de la version 5.4.0, incluse, à la version 6.0.0, exclusive.) Cliquez sur Suivant.

Fenêtre Xcode avec les options de la version du package, de la branche et du commit

Enfin, sélectionnez les produits du package et les cibles à ajouter au projet. Sélectionnez les deux, Realm et RealmSwift, puis cliquez sur terminer. Xcode télécharge le code à partir du référentiel et ajoute le package Realm à la cible PotionsMasrer.

Fenêtre Xcode avec une liste de cibles à sélectionner

Construisez et exécutez pour être sûr que tout fonctionne.

Liste des ingrédients et ingrédients achetés

Maintenant que vous avez configuré Realm, vous êtes prêt à créer votre premier modèle de données.

Définition de votre modèle de données de domaine

Pour créer votre modèle d’ingrédients, ajoutez un nouveau fichier Swift dans le Des modèles groupe et nommez-le IngrédientDB.swift. Ajoutez le code suivant:

import RealmSwift
// 1
class IngredientDB: Object {
  // 2
  @objc dynamic var id = 0
  @objc dynamic var title = ""
  @objc dynamic var notes = ""
  @objc dynamic var quantity = 1
  @objc dynamic var bought = false

  // 3
  override static func primaryKey() -> String? {
    "id"
  }
}

Voici un aperçu du code que vous venez d’ajouter:

  1. Tout d’abord, vous définissez votre classe, la sous-classification Object, Classe de base de Realm pour tous les modèles de données. Vous utiliserez ce cours pour enregistrer vos ingrédients dans Realm.
  2. Ici, vous définissez chaque Ingredient propriété que vous souhaitez que Realm stocke.
  3. Enfin, vous remplacez primaryKey() pour indiquer à Realm quelle propriété est la clé primaire du modèle. Realm utilise des clés primaires pour appliquer l’unicité. Une clé primaire fournit également un moyen efficace de récupérer et de mettre à jour des données.

C’est tout!

Vous définissez les modèles de données Realm comme des classes Swift régulières. Realm utilise ces classes pour écrire vos données sur le disque, mais il existe certaines restrictions spécifiques à Object sous-classes. En raison de sa nature multiplateforme, Realm ne prend en charge qu’un ensemble limité de types de propriétés indépendants de la plate-forme. Certaines de ces propriétés sont:

  • Booléen
  • Int
  • Double
  • Flotte
  • Chaîne
  • Date
  • Les données

Optional les propriétés ont des restrictions spéciales. Vous pouvez déclarer String, Date, et Data comme facultatif. Pour le reste, vous utilisez la classe wrapper RealmOptional; sinon, ils doivent avoir une valeur.

Chaque propriété a le @objc dynamic mots clés. Cela les rend accessibles au moment de l’exécution via Répartition dynamique. Realm utilise cette fonctionnalité Swift et Objective-C pour créer une façade entre la lecture et l’écriture de données. Lors de l’accès à une propriété, Swift délègue à Realm la responsabilité de vous fournir les données souhaitées.

Définition des relations

Realm prend également en charge les relations. Vous pouvez déclarer des objets imbriqués pour créer des relations plusieurs-à-un. Et vous pouvez utiliser List pour créer des relations plusieurs-à-plusieurs. Lors de la déclaration d’un List, Realm enregistre ces objets imbriqués avec votre modèle de données.

Ajout d’un initialiseur

Avant de continuer, ouvrez Ingrédient.swift et ajoutez l’extension suivante au bas du fichier:

// MARK: Convenience init
extension Ingredient {
  init(ingredientDB: IngredientDB) {
    id = ingredientDB.id
    title = ingredientDB.title
    notes = ingredientDB.notes
    bought = ingredientDB.bought
    quantity = ingredientDB.quantity
  }
}

Cette extension crée un initialiseur pratique pour le mappage IngredientDB à Ingredient. Vous l’utiliserez plus tard dans le projet.

Maintenant que vous avez défini votre modèle de données, il est temps d’ajouter un objet à votre base de données.

Ajout d’objets à la base de données

dans le VoirModèles groupe, ouvert IngredientStore.swift. Importer RealmSwift en ajoutant la ligne suivante en haut du fichier:

import RealmSwift

Ensuite, remplacez le corps de create(title:notes:quantity:) avec le code suivant:

objectWillChange.send()

Tout d’abord, vous envoyez un signal à SwiftUI. Parce que IngredientStore est un ObservableObject, SwiftUI souscrit à objectWillChange et répond au signal en rechargeant sa vue.

Ensuite, ajoutez le code suivant à la méthode:

do {
  let realm = try Realm()

  let ingredientDB = IngredientDB()
  ingredientDB.id = UUID().hashValue
  ingredientDB.title = title
  ingredientDB.notes = notes
  ingredientDB.quantity = quantity
} catch let error {
  // Handle error
  print(error.localizedDescription)
}

Tout d’abord, créez une instance de Realm en ouvrant le royaume par défaut. Avec lui, vous pouvez écrire, lire, mettre à jour et supprimer des objets. Ensuite, créez un IngredientDB objet et définissez ses valeurs de propriété à partir des paramètres de la méthode.

Vous pouvez instancier et utiliser des modèles de données Realm comme tout autre objet Swift. Vous appelez ces objets non gérés. Cela signifie que la base de données ne les connaît pas encore et que les modifications ne seront pas conservées. Une fois que vous avez ajouté un objet à un royaume, il est géré par Realm. Cela signifie que Realm stocke l’objet sur le disque et garde une trace de ses modifications.

Ajoutez le modèle au royaume en ajoutant ces quelques lignes au code à la fin du do bloquer:

try realm.write {
  realm.add(ingredientDB)
}

Vous démarrez une transaction d’écriture en appelant write sur le Realm. Chaque opération que vous effectuez sur un domaine doit être à l’intérieur de ce bloc de transaction d’écriture, y compris les ajouts, les suppressions et les mises à jour. Dans la transaction, vous ajoutez la nouvelle instance de IngredientDB au royaume. Realm stocke maintenant l’objet et suit ses modifications, ce qui en fait un objet géré.

Construisez et exécutez, puis allez-y et créez un ingrédient! Robinet Nouvel ingrédient, donnez-lui un titre et appuyez sur sauvegarder.

Formulaire des ingrédients avec quantité de titre et notes

Mais attendez, quelque chose ne va toujours pas. Vous créez un ingrédient, mais rien ne se passe! Il répertorie toujours les mêmes ingrédients qu’avant.

C’est parce que IngredientStore ne fait pas chercher ingrédients de Realm encore – il utilise toujours les données factices. Vous allez résoudre ce problème ensuite.

Récupération d’objets

Ouvert IngredientStore.swift à nouveau, et recherchez ce qui suit:

var ingredients: [Ingredient] = IngredientMock.ingredientsMock
var boughtIngredients: [Ingredient] = IngredientMock.boughtIngredientsMock

Remplacez ce code par ceci:

private var ingredientResults: Results
private var boughtIngredientResults: Results

Lors de l’extraction d’objets de Realm, la base de données renvoie un Results type. Ce type représente une collection d’objets récupérés à partir de requêtes.

Ajoutez maintenant l’initialiseur suivant sous les deux lignes que vous venez d’ajouter:

// 1
init(realm: Realm) {
  // 2
  ingredientResults = realm.objects(IngredientDB.self)
    .filter("bought = false")
  // 3
  boughtIngredientResults = realm.objects(IngredientDB.self)
    .filter("bought = true")
}

Voici ce qui se passe dans l’initialiseur ci-dessus:

  1. Tout d’abord, vous recevez une instance de Realm. Vous utiliserez cette instance pour récupérer des ingrédients.
  2. Ensuite, vous récupérez les ingrédients de realm et filtrez-les avec bought comme false.
  3. Ensuite, vous récupérez les ingrédients de realm et filtrez-les avec bought comme true.

Enfin, insérez le code suivant après l’initialiseur:

var ingredients: [Ingredient] {
  ingredientResults.map(Ingredient.init)
}

var boughtIngredients: [Ingredient] {
  boughtIngredientResults.map(Ingredient.init)
}

Ces propriétés transforment le royaume Result dans un tableau régulier. L’interface utilisateur de l’exemple de projet utilise ces propriétés calculées pour mapper les modèles de base de données aux vues.

Puisque IngredientStore nécessite maintenant un Realm dans son initialiseur, vous devez le fournir. Ouvert ScenceDelegate.swift. Après le import SwiftUI déclaration, importation RealmSwift en insérant ce qui suit:

import RealmSwift

Ensuite, changez le code à l’intérieur scene(_:willConnectTo:options:) pour ça:

if let windowScene = scene as? UIWindowScene {
  do {
    // 1
    let realm = try Realm()
    let window = UIWindow(windowScene: windowScene)
    // 2
    let contentView = ContentView()
      .environmentObject(IngredientStore(realm: realm))
    window.rootViewController = UIHostingController(rootView: contentView)
    self.window = window
    window.makeKeyAndVisible()
  } catch let error {
    // Handle error
    fatalError("Failed to open Realm. Error: (error.localizedDescription)")
  }
}

Voici ce que vous faites:

  1. Vous créez une nouvelle instance de Realm.
  2. Vous instanciez IngredientStore avec le Realm instance, et vous l’ajoutez au ContentViews environnement.

Construisez et exécutez. Maintenant, créez un ingrédient et voyez la magie!

Formulaire des ingrédients avec quantité de titre et notes

Le royaume fonctionne avec Objets vivants. Lorsque vous ajoutez un ingrédient à Realm, ingredientResults se met à jour automatiquement sans que vous ayez besoin de le récupérer à chaque fois. SwiftUI reçoit un signal pour mettre à jour l’interface utilisateur avec une nouvelle vue à jour. On dirait de la magie, non? Allez-y et créez d’autres ingrédients! :]

Maintenant que vous pouvez ajouter un ingrédient avec succès, il est temps de créer la fonctionnalité pour mettre à jour les ingrédients existants.

Mettre à jour des objets

Une caractéristique clé de PotionsMaster est la possibilité de basculer un ingrédient ACHETÉ liste. Pour le moment, si vous appuyez sur le bouton d’achat, rien ne se passe. Pour résoudre ce problème, vous utilisez Realm pour mettre à jour les ingrédients sur le disque.

Basculer les ingrédients à ACHETER

Pour déplacer un ingrédient vers ACHETÉ list, vous devez mettre à jour la valeur de propriété de bought à true sur disque.

Ouvert IngredientStore.swift et remplacer le contenu de toggleBought(ingredient:) avec ce qui suit:

// 1
objectWillChange.send()
do {
  // 2
  let realm = try Realm()
  try realm.write {
    // 3
    realm.create(
      IngredientDB.self,
      value: ["id": ingredient.id, "bought": !ingredient.bought],
      update: .modified)
  }
} catch let error {
  // Handle error
  print(error.localizedDescription)
}

Voici ce qui se passe dans ce code:

  1. Vous envoyez un signal à SwiftUI indiquant que l’objet est sur le point de changer.
  2. Vous ouvrez le royaume par défaut.
  3. Vous démarrez une nouvelle transaction d’écriture et appelez create(_:value:update:), en passant les valeurs mises à jour et le .modified Cas. Cela indique à Realm de mettre à jour la base de données avec les valeurs contenues dans le dictionnaire. Lors de la création du dictionnaire, vous devez inclure l’objet id. Si un objet avec ça id existe déjà, Realm le met à jour avec les nouvelles valeurs. Sinon, Realm crée un nouvel objet sur le disque.

Construisez et exécutez. Achetez maintenant un ingrédient en appuyant sur l’icône circulaire à droite de sa cellule.

Liste des ingrédients. Curseur tapant sur le bouton d'achat et déplaçant l'ingrédient vers la section achetée.

Lors de la mise à jour bought, Le royaume informe les deux ingredientResults et boughtIngredientResults de ce changement. L’ingrédient mis à jour passe à boughtIngredientResults. Et SwiftUI anime le changement sur le List! À quel point cela est cool? :]

Une autre façon de mettre à jour un objet consiste à définir ses propriétés sur de nouvelles valeurs. Encore une fois, vous faites cela dans une transaction d’écriture. Realm mettra alors à jour chaque valeur sur le disque.

Mise à jour d’autres propriétés

Maintenant que vous savez comment mettre à jour un objet, vous pouvez utiliser Realm pour mettre à jour d’autres propriétés tout aussi facilement. Changer le corps de update(ingredientID:title:notes:quantity:) au code ci-dessous:

// 1
objectWillChange.send()
do {
  // 2
  let realm = try Realm()
  try realm.write {
    // 3
    realm.create(
      IngredientDB.self,
      value: [
        "id": ingredientID,
        "title": title,
        "notes": notes,
        "quantity": quantity
      ],
      update: .modified)
  }
} catch let error {
  // Handle error
  print(error.localizedDescription)
}

Voici ce qui se passe dans ce code:

  1. Encore une fois, vous utilisez objectWillChange pour envoyer un signal indiquant à SwiftUI de recharger l’interface utilisateur.
  2. Vous ouvrez le royaume par défaut.
  3. Tu appelles create(_:value:update:) dans une transaction d’écriture. Cet appel met à jour les valeurs de l’ingrédient.

Ceci est similaire au code que vous avez ajouté ci-dessus pour acheter un ingrédient. Tu appelles create(_:value:update:), en passant les valeurs mises à jour. Realm met à jour les valeurs sur le disque et notifie ingredientResults des changements. Ensuite, SwiftUI met à jour l’interface utilisateur avec ces modifications.

Construisez et exécutez. Appuyez sur le nom d’un ingrédient pour ouvrir à nouveau le formulaire. Modifiez certains champs et appuyez sur Mise à jour.

Liste des ingrédients et ingrédients achetés. Curseur tapant sur un ingrédient ouvrant le formulaire avec lui et mettant à jour son titre.

Maintenant, tout ce qui reste est suppression Ingrédients!

Supprimer des objets

Appuyez sur le acheter le bouton déplace un ingrédient vers ACHETÉ section. Mais une fois qu’il est là, vous ne pouvez pas vous en débarrasser. Appuyer sur l’icône de la corbeille ne fait rien.

Pour résoudre ce problème, ouvrez IngredientStore.swift. Remplacez le corps de delete(ingredientID:) avec le code suivant:

// 1
objectWillChange.send()
// 2
guard let ingredientDB = boughtIngredientResults.first(
  where: { $0.id == ingredientID }) 
  else { return }

do {
  // 3
  let realm = try Realm()
  try realm.write {
    // 4
    realm.delete(ingredientDB)
  }
} catch let error {
  // Handle error
  print(error.localizedDescription)
}

Voici comment supprimer un ingrédient de ce code:

  1. Encore une fois, vous utilisez objectWillChange pour envoyer un signal demandant à SwiftUI de recharger l’interface utilisateur.
  2. Vous trouvez l’ingrédient à supprimer boughtIngredientResults.
  3. Vous ouvrez le royaume par défaut.
  4. Enfin, vous appelez delete, en passant l’objet que vous souhaitez supprimer.

Construisez et exécutez. Achetez un ingrédient, puis appuyez sur le bouton Supprimer pour le supprimer de la liste.

Liste des ingrédients et ingrédients achetés. Curseur en appuyant sur le bouton d'achat déplaçant un ingrédient vers la section achetée, puis en appuyant sur le bouton de suppression sur les deux sections achetées.

Ajout d’une nouvelle propriété à un objet de domaine

Pendant le développement, il est courant que les modèles de données se développent et évoluent. Les types de propriétés peuvent changer et vous devrez peut-être ajouter ou supprimer des propriétés. Avec Realm, changer votre modèle de données est aussi simple que de changer n’importe quelle autre classe Swift.

Dans cette section, vous allez ajouter une nouvelle propriété pour identifier vos ingrédients par couleur.

Ouvert IngrédientDB.swift et ajoutez une nouvelle propriété sous bought:

@objc dynamic var colorName = "rw-green"

Ensuite, dans Ingrédient.swift, ajoutez la propriété suivante:

var colorName = "rw-green"

Vous devez également mettre à jour l’initialiseur pour définir colorName. Ajoutez la ligne suivante en bas de l’initialiseur dans le fichier:

colorName = ingredientDB.colorName

Dans les trois lignes de code ci-dessus, vous avez ajouté une propriété pour stocker le nom de la couleur sur Realm et pour le mapper dans les vues.

C’est tout! Les modèles sont prêts à stocker un nom de couleur. Ensuite, vous mettrez à jour IngredientStore.swift pour enregistrer cette nouvelle propriété dans votre base de données.

Stockage de la nouvelle propriété dans le royaume

Ouvert IngredientStore.swift, et recherchez ce code:

func create(title: String, notes: String, quantity: Int) {

Remplacez-le par ceci:

func create(title: String, notes: String, quantity: Int, colorName: String) {

Maintenant, insérez la ligne suivante après où vous avez défini d’autres propriétés comme quantity et notes:

ingredientDB.colorName = colorName

Cela ajoute un nouveau paramètre, colorName, et l’attribue à ingredientDB.

Toujours dedans IngredientStore.swift, trouvez cette ligne:

func update(ingredientID: Int, title: String, notes: String, quantity: Int) {

Changez-le en ceci:

func update(
  ingredientID: Int,
  title: String,
  notes: String,
  quantity: Int,
  colorName: String
) {

Enfin, dans update, trouvez ce code:

realm.create(
  IngredientDB.self,
  value: [
    "id": ingredientID,
    "title": title,
    "notes": notes,
    "quantity": quantity
  ], 
  update: .modified)

Remplacez-le par ce qui suit:

realm.create(
  IngredientDB.self,
  value: [
    "id": ingredientID,
    "title": title,
    "notes": notes,
    "quantity": quantity,
    "colorName": colorName
  ],
  update: .modified)

Ce code ajoute un paramètre, colorName, à la mise à jour. Il l’ajoute au dictionnaire de valeurs lors de l’appel create(_:value:update:).

Désormais, les méthodes de création et de mise à jour nécessitent une colorName.

Mais Xcode reconnaît que IngredientFormView ne passe pas un colorName quand il appelle ces méthodes et produit quelques erreurs.

Pour résoudre ce problème, ouvrez IngredientForm.swift. Ajoutez le code suivant juste après la propriété quantity:

@Published var color = ColorOptions.rayGreen

Maintenant trouver init(_:ingredient:) et ajoutez la ligne suivante en bas:

color = ColorOptions(rawValue: ingredient.colorName) ?? .rayGreen

Ici, vous ajoutez une propriété pour stocker la couleur lorsque l’utilisateur crée ou met à jour un ingrédient.

Ensuite, ouvrez IngredientFormView.swift et trouvez le code suivant à l’intérieur saveIngredient():

store.create(
  title: form.title,
  notes: form.notes,
  quantity: form.quantity)

Remplacez-le par ceci:

store.create(
  title: form.title,
  notes: form.notes,
  quantity: form.quantity,
  colorName: form.color.name)

Dans updateIngredient(), tu dois réussir colorName dans l’appel à update. Pour ce faire, recherchez le code suivant:

store.update(
  ingredientID: ingredientID,
  title: form.title,
  notes: form.notes,
  quantity: form.quantity)

Remplacez-le par ceci:

store.update(
  ingredientID: ingredientID,
  title: form.title,
  notes: form.notes,
  quantity: form.quantity,
  colorName: form.color.name)

Vous avez maintenant résolu le problème de IngredientFormView ne pas passer colorName à IngredientStore.

Construisez et exécutez. Et vous obtenez…

Message sur le terminal indiquant qu'une propriété a été ajoutée et qu'une migration est requise.

L’application plante! Realm génère une erreur de migration: Migration is required due to the following errors:. Mais pourquoi cela se produit-il?

Travailler avec les migrations

Lorsque votre application est lancée, Realm analyse votre code pour les classes avec Object sous-classes. Quand il en trouve un, il crée un schéma pour mapper le modèle à la base de données.

Lorsque vous modifiez un modèle de données, il existe une incompatibilité entre le nouveau schéma et celui de la base de données. Si cela se produit, Realm génère une erreur. Vous devez indiquer à Realm comment migrer l’ancien schéma vers le nouveau. Sinon, il ne sait pas comment mapper d’anciens objets sur le nouveau schéma.

Depuis que vous avez ajouté une nouvelle propriété, colorName, à IngredientDB, vous devez créer une migration pour celui-ci.

Remarque: Vous pouvez résoudre ce problème pendant le développement en passant true à deleteRealmIfMigrationNeeded lorsque vous instanciez Realm.Configuration. Cela indique à Realm que, s’il doit migrer, il doit supprimer son fichier et en créer un nouveau.

Créer une migration

dans le Des modèles groupe, créez un fichier nommé RealmMigrator.swift.

Maintenant, ajoutez ce code à votre nouveau fichier:

import RealmSwift

enum RealmMigrator {
  // 1
  static private func migrationBlock(
    migration: Migration,
    oldSchemaVersion: UInt64
  ) {
    // 2
    if oldSchemaVersion < 1 {
      // 3
      migration
        .enumerateObjects(ofType: IngredientDB.className()) { _, newObject in
          newObject?["colorName"] = "rw-green"
        }
    }
  }
}

Voici la répartition:

  1. Vous définissez une méthode de migration. La méthode reçoit un objet de migration et oldSchemaVersion.
  2. Vous vérifiez la version du schéma persistant dans les fichiers pour décider de la migration à exécuter. Chaque schéma a un numéro de version, à partir de zéro. Dans ce cas, si l'ancien schéma est le premier (avant d'ajouter une nouvelle propriété), exécutez la migration.
  3. Enfin, pour chacun des anciens et des nouveaux IngredientDB objets dans Realm, vous attribuez une valeur par défaut à la nouvelle propriété.

Utilisations du royaume migrationBlock pour exécuter la migration et mettre à jour toutes les propriétés nécessaires.

En bas de RealmMigrator, ajoutez le nouveau static méthode:

static func setDefaultConfiguration() {
  // 1
  let config = Realm.Configuration(
    schemaVersion: 1,
    migrationBlock: migrationBlock)
  // 2
  Realm.Configuration.defaultConfiguration = config
}

Voici ce que vous faites dans ce code:

  1. Vous créez une nouvelle instance de Realm.Configuration en utilisant votre migrationBlocket définissez la version actuelle du schéma sur 1.
  2. Vous définissez la nouvelle configuration par défaut de Realm.

Enfin, dans SceneDelegate.swift, appelez cette nouvelle méthode en haut de scene(_:willConnectTo:options:):

RealmMigrator.setDefaultConfiguration()

Realm utilise cette configuration pour ouvrir la base de données par défaut. Lorsque cela se produit, Realm détecte une incompatibilité entre le schéma conservé par fichier et le nouveau schéma. Il migre ensuite les modifications en exécutant la fonction de migration que vous venez de créer.

Maintenant, construisez et exécutez à nouveau. Cette fois, le crash est parti!

Liste des ingrédients et ingrédients achetés.

Vous avez ajouté avec succès une nouvelle propriété à IngredientDB. Et vous vous êtes occupé de la migration. Il est maintenant temps de mettre à jour le formulaire pour que l'utilisateur puisse choisir la couleur!

Ajout d'un nouveau champ au formulaire

Ouvert IngredientFormView.swift et trouvez le commentaire // TODO: Insert Picker here. Insérez ce code sous la ligne de commentaire:

Picker(selection: $form.color, label: Text("Color")) {
  ForEach(colorOptions, id: .self) { option in
    Text(option.title)
  }
}

Cela ajoute une nouvelle vue de sélecteur à IngredientFormView. Ce sélecteur permet à l'utilisateur de choisir une couleur.

Ensuite, ouvrez IngrédientRow.swift et trouvez le commentaire // TODO: Insert Circle view here. Ajoutez le code suivant après le commentaire:

Circle()
  .fill(Color(ingredient.colorName))
  .frame(width: 12, height: 12)

Ici, vous ajoutez une vue circulaire à chaque ligne d'ingrédients. Vous remplissez le cercle avec la couleur de cet ingrédient.

Construisez et exécutez pour voir les changements. Créez maintenant un nouvel ingrédient et sélectionnez-en une couleur.

Forme d'ingrédient. Le curseur sélectionne la couleur dans une liste et enregistre l'ingrédient. Liste des ingrédients avec un ingrédient avec la couleur choisie.

Bon travail! Vous pouvez maintenant lister tous les ingrédients dont vous avez besoin pour cette potion spéciale que vous préparez. :]

Où aller en partant d'ici

Vous pouvez télécharger le projet final en cliquant sur le Télécharger les matériaux bouton en haut ou en bas du didacticiel.

Dans ce didacticiel SwiftUI Realm, vous avez appris à créer, mettre à jour, récupérer et supprimer des objets de Realm à l'aide de SwiftUI. En plus des bases, vous avez également découvert les migrations et comment les créer.

Pour en savoir plus sur Realm, vous pouvez vous référer à son documentation officielle. Et n'oubliez pas de consulter notre livre, Realm: créer des applications Swift modernes avec la base de données Realm.

Si vous souhaitez en savoir plus sur SwiftUI, consultez notre SwiftUI par Tutoriels.

J'espère que vous avez apprécié ce tutoriel. Si vous avez des questions ou des commentaires, n'hésitez pas à participer à la discussion ci-dessous.

Close Menu