Formation PUB900 : Développer une application pour iPhone avec SwiftUI, H-2024 CRUD avec SwiftData

42.1 Opérations CRUD avec SwiftData (ajouter, modifier ou supprimer des données)


Avec SwiftData, effectuer des opération CRUD (Create, Read, Update, Delete) est un charme.

Dans cette fiche :

Insert

L'insertion de données consiste à instancier un nouvel objet puis à faire appel à modelContext.insert().

Je vous présente ici l'insertion à l'intérieur de ContentView mais cela pourrait avoir lieu dans n'importe quelle autre vue.

SwiftUI

import SwiftData
...

struct ContentView: View {
  @Environment(\.modelContext) var modelContext
  ...

  var body: some View {
    ...
    Button(action: {
      let item = Item(code: "abc", titre: "Item abc")
      modelContext.insert(item)
      do {
        try modelContext.save()
      } catch {
        print("Impossible d'insérer l'item: \(error)")
        ... // mécanisme pour afficher un message à l'usager
      }
    }) {
      Text("Enregistrer")
    }
    .buttonStyle(.bordered)
    ...
  }
}

Delete

Pour supprimer un enregistrement, il est important d'avoir en main un objet qui a été instancié à partir d'une requête.

La façon la plus traditionnelle consiste à créer le bouton de suppression à même la liste qui affiche les données.

Suppression simple

Le traitement consistera à appeler modelContext.delete().

SwiftUI

List(items) { item in
  VStack(alignment: .leading) {
    HStack {
      Text("\(item.code) - \(item.titre)")
      Spacer()
      Button(
        role: .destructive,
        action: {
          modelContext.delete(item)
          do {
            try modelContext.save()
          } catch {
            print("Impossible de supprimer l'item: \(error)")
            ... // mécanisme pour afficher un message à l'usager
          }
      }) {
        Image(systemName: "trash")
      }
    }
  }
}

Confirmation avant suppression

Il est d'usage de demander confirmation avant suppression puisque cette opération est irréversible.

La technique est expliquée dans la fiche « Demander une confirmation avec .confirmationDialog() ».

Il faudra adapter le code présenté afin qu'il fasse un modelContext.delete() plutôt que de retirer un élément d'un tableau.

Vider une table entière

Pour supprimer tous les enregistrements d'une table, il suffit d'appeler la méthode delete() avec le modèle comme paramètre.

SwiftUI

do {
  try modelContext.delete(model: Item.self)
  try modelContext.save()
} catch {
  print("Impossible de supprimer tous les items.")
  ...  // mécanisme pour afficher un message à l'usager
}

Update

La mise à jour sera généralement effectuée à partir d'un formulaire qui aura été affiché à partir de la liste d'items. On sera ainsi assurés que c'est le bon enregistrement qui est mis à jour.

Contrairement à l'ajout et à la suppression, il suffit de mettre à jour l'objet pour que les données soient enregistrées dans la base de données.

SwiftUI

Button(
  action: {
    item.code = code
    item.titre = titre
    do {
      try modelContext.save()
    } catch {
      print("Impossible de mettre à jour l'item: \(error)")
      ... // mécanisme pour afficher un message à l'usager
    }
}) {
  Text("Enregistrer")
}

Dangers de l'enregistrement automatique sans save()

Par défaut, les modifications au modelContext seront automatiquement réflétées dans la base de données, sans nécessiter un appel à modelContext.save(). Ce comportement est pratique mais il n'est pas sans danger. De plus, il peut être désactivé.

Quand l'enregistrement automatique est activé, l'usager aura l'impression que les données sont enregistrées sur-le-champ. Dans les faits, l'enregistrement aura lieu à des moments précis, par exemple lorsque l'application passe en arrière-plan ou revient au premier-plan ou encore lorsque la boucle courante se termine. Ce délai peut être de quelques fractions de secondes mais s'étire parfois sur plusieurs secondes.

Il y a des situations où ce délai peut causer des mauvais fonctionnements de l'application, par exemple :

  • Le cas le plus classique survient si l'application est refermée immédiatement après la mise à jour en mémoire, avant que l'enregistrement sur disque n'ait été réalisé. Les modifications sont alors perdues.
  • Le délai d'enregistrement peut également poser problème si on ajoute un enregistrement puis qu'on appelle immédiatement une fonction qui utilise cet enregistrement.

Dans tous les cas, pour assurer que l'enregistrement soit réalisé sans délai, il faut faire appel à modelContext.save().

Dans cet exemple, le code doit appeler une fonction qui synchronise la base de données locale avec une base de données distante via un service Web.

SwiftUI

let item = Item(code: "abc", titre: "Item abc")
modelContext.insert(item)

do {
   try modelContext.save() // sans ceci, l'item n'est pas encore disponible pour la synchro
} catch {
  print("Impossible d'ajouter l'item: \(error)")
  ...   // mécanisme pour afficher un message à l'usager
}

synchroniserBD()

Erreur « Thread 1: Fatal error: Observation Registrar was not found on Model »

Si vous obtenez l'erreur « Thread 1: Fatal error: Observation Registrar was not found on Model » lors de l'ajout, de la modification ou de la suppresison d'un enregistrement, assurez-vous que le modèle ne répond pas au protocole CustomReflectable.

En effet, il semble y avoir un conflit entre le protocole CustomReflectable et le mécanisme d'observation utilisé par SwiftData.

Pour plus d'information

« Adding and editing persistent data in your app ». Apple. https://developer.apple.com/documentation/swiftdata/adding-and-editing-persistent-data-in-your-app/

« Deleting persistent data from your app ». Apple. https://developer.apple.com/documentation/swiftdata/deleting-persistent-data-from-your-app

« Creating, editing, and deleting model objects ». Hacking with Swift. https://www.hackingwithswift.com/quick-start/swiftdata/creating-editing-and-deleting-model-objects

«  When does SwiftData autosave data?  ». Hacking with Swift. https://www.hackingwithswift.com/quick-start/swiftdata/when-does-swiftdata-autosave-data

« How to save a SwiftData object ». Hacking with Swift. https://www.hackingwithswift.com/quick-start/swiftdata/how-to-save-a-swiftdata-object

▼Publicité

Veuillez noter que le contenu de cette fiche vous est partagé à titre gracieux, au meilleur de mes connaissances et sans aucune garantie.
Merci de partager !
Soumettre