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

37.7 Requêtes pour retrouver les données de la base de données (@Query)


Une fois que votre modèle a été adapté pour SwiftData, il est tout simple d'effectuer une requête pour afficher les données dans votre application.

Notez que la création de la base de données et de ses tables à partir des modèles est prise en charge par SwiftData.

Notez également que les données peuvent avoir été insérées par l'une de ces techniques :

Dans cette fiche :

Requête simple

Pour retrouver les données, il faut ajouter l'instruction import SwiftData dans le haut de la vue dans laquelle on désire effectuer une requête, par exemple ContentView.

Pour effectuer la requête, on déclarera une variable dans la vue à l'aide de la macro @Query.

SwiftUI

import SwiftUI
import SwiftData

struct ContentView: View {

  @Query var items: [Item]

  var body: some View {
    ...
  }
}

Ceci retournera un tableau de modèles.

Les modifications aux données de ce tableau forceront immédiatement le rafraîchissement de la vue, comme s'il s'agissait d'une variable d'état.

La requête sera effectuée dès l'affichage de la vue qui contient la macro @Query.

La variable ainsi initialisée peut être utilisée dans la vue au même titre que toute autre variable.

SwiftUI

List {
  ForEach(items) { item in
    VStack(alignment: .leading) {
      Text("\(item.code) - \(item.titre)")
    }
  }
}

Enchaînement d'objets

Lorsqu'il y a une relation entre deux tables, les données de la secondes table pourront être retrouvées en enchaînant les objets.

SwiftUI

Text(item.categorie.titre)

Notez qu'un tel enchaînement ne fonctionne qu'après l'exécution du @Query.

En effet, SwiftData ne supporte pas encore les jointures lors de la requête. Il est donc impossible de filtrer ou trier à l’aide d’une propriété d’une relation.

Ceci ne fonctionnera pas :

SwiftUI

@Query(sort: \Item.categorie.titre) var items: [Item]

Variable observable

La variable initialisée par @Query (ici : items) est observable, c'est-à-dire que lorsque sa valeur change, les modifications sont reflétées automatiquement partout où la variable est utilisée, même dans une autre vue de l'application.

Ceci est pratique puisque lorsque vous modifiez des données de la base de données, par exemple lorsque vous faites un ajout ou une suppression, vous n'avez pas besoin de vous occuper de mettre la liste d'items à jour.

SwiftUI

Button(action: {
  ...
  modelContext.insert(item)   // ceci ajoute l'item dans la BD et met à jour la variable items initialisée par @Query
  ...
}) {
  Text("Enregistrer")
}

Tri

Comme pour toute application qui travaille avec des données, lorsque des informations doivent être affichées dans une application SwiftData, il faut que la requête les trie selon une des informations affichées.

SwiftUI

@Query(sort: \Item.code) var items: [Item]

ou encore :

SwiftUI

@Query(sort: \Item.code, order: .reverse) var items: [Item]

Si vous avez besoin de trier à l'aide de plus d'une clé, vous devrez travailler avec un SortDescriptor.

SwiftUI

@Query(sort: [SortDescriptor(\Eleve.nomFamille), SortDescriptor(\Eleve.prenom)]) var eleves: [Eleve]

ou, pour faciliter la lecture du code :

SwiftUI

@Query(
  sort: [
    SortDescriptor(\Eleve.nomFamille),
    SortDescriptor(\Eleve.prenom)
  ]
)
var eleves: [Eleve]

Filtre

Pour ne retrouver que certains enregistrements, on procédera comme suit :

SwiftUI

@Query(filter: #Predicate<Item> { $0.titre.contains("A") }) var items: [Item]

Ou encore une combinaison de tri et de filtre :

SwiftUI

@Query(filter: #Predicate<Item> { $0.titre.contains("A") }, sort: \Item.code) var items: [Item]

Animation

Lorsqu'on retrouve des données avec la macro @Query, il est possible de spécifier le type d'animation qui sera effectuée lorsque les données sont modifiées.

SwiftUI

@Query(sort: \Item.code, order: .forward, animation: .linear) var items: [Item]

Requête en dehors d'une vue

La macro @Query n'est disponible que dans une vue.

Si vous avez besoin d'effectuer une requête en dehors d'une vue, par exemple dans une méthode d'une classe, vous pouvez utiliser FetchDescriptor.

SwiftUI

do {

  let container = try ModelContainer(for: Item.self)
  let descriptor = FetchDescriptor<Item>(
    sortBy: [SortDescriptor(\.code)]
  )
  let items = try container.mainContext.fetch(descriptor)
  ...
}
catch {
  print("Impossible de retrouver les items.")
}

Pour plus d'information

« Filtering and sorting persistent data ». Apple. https://developer.apple.com/documentation/swiftdata/filtering-and-sorting-persistent-data

« How to Query and Filter Data in SwiftData with Predicate ». Swifty Place. https://www.swiftyplace.com/blog/fetch-and-filter-in-swiftdata

▼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