Génie civil & structural
Utilisation des données de base avec Nsfetchedresultscontroller pour les données dynamiques dans Ios
Table of Contents
Introduction: Pourquoi les données de base et les résultats NSFetchedMatière de contrôleur
Dans le développement moderne d'iOS, fournir une interface utilisateur fluide et réactive dépend souvent de l'efficacité avec laquelle votre application gère les données qui changent au fil du temps. Que vous construisiez un flux social, un gestionnaire de tâches ou un système d'inventaire, les données affichées aux utilisateurs sont rarement statiques. Core Data — Le graphique d'objets matures d'Apple et le cadre de persistance — jumelés à (FRC) offrent une solution éprouvée pour gérer des ensembles de données dynamiques à grande échelle tout en gardant l'interface utilisateur synchronisée sans frais généraux manuels.
Cet article fournit un guide pratique et approfondi pour l'utilisation des données de base avec les notifications . Lorsque des objets sont insérés, mis à jour ou supprimés, le contexte diffuse ces changements, ce qui est précisément ce que leviers pour garder votre UI cohérente.
Pour la documentation officielle du développeur, veuillez consulter Référence au cadre de données de base d'Apple[.
NSFetchedRésultatsContrôleur: le pont entre les données de base et votre UI
est un objet de contrôleur conçu pour gérer efficacement les résultats retournés à partir d'une requête de récupération de données de base, surtout lorsque les données sous-jacentes sont censées changer. Il surveille le contexte d'objet géré pertinent et signale automatiquement les changements via son protocole délégué.
Caractéristiques principales
- Suivi automatique des changements :[ Le FRC écoute les notifications contextuelles et les traduit en rappels de délégués structurés (, , .
- Construire la section :[ En spécifiant un , le contrôleur regroupe les résultats dans les sections, ce qui rend anodin d'afficher les vues de table ou de collection sectionnées.
- Optimisation du rendement :[ Le FRC utilise la faille et le cache sous le capot. Il ne récupère les données que si nécessaire et peut utiliser un cache persistant pour éviter de re-fetching lorsque le contexte d'objet géré est sauvegardé.
Méthodes de délégation en détail
Pour bénéficier pleinement du contrôleur, vous devez mettre en œuvre le . Le modèle le plus courant est d'utiliser ces rappels à l'intérieur d'un ou délégué pour mettre à jour l'interface utilisateur par lots. Par exemple :
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.beginUpdates()
}
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>,
didChange anObject: Any,
at indexPath: IndexPath?,
for type: NSFetchedResultsChangeType,
newIndexPath: IndexPath?) {
switch type {
case .insert:
tableView.insertRows(at: [newIndexPath!], with: .fade)
case .delete:
tableView.deleteRows(at: [indexPath!], with: .fade)
case .update:
tableView.reloadRows(at: [indexPath!], with: .fade)
case .move:
tableView.moveRow(at: indexPath!, to: newIndexPath!)
@unknown default:
tableView.reloadData()
}
}
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.endUpdates()
}
Ce modèle permet d'assurer que la vue de la table anime les changements en synchronisation avec les données sous-jacentes, en évitant le scintillement ou l'incohérence.
Mise en œuvre étape par étape
Ci-dessous est un exemple complet et prêt à la production utilisant Swift 5, ciblant iOS 15+. Nous allons supposer une entité simple appelée avec des attributs (String) et (Bool), et un (Date).
1. Configuration de la pile de données de base
Dans votre ou un dédié] (commun dans les applications SwiftUI), créez le conteneur persistant:
class PersistenceController {
static let shared = PersistenceController()
let container: NSPersistentContainer
init() {
container = NSPersistentContainer(name: "YourModelName")
container.loadPersistentStores { storeDescription, error in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
}
container.viewContext.automaticallyMergesChangesFromParent = true
}
}
2. Créer la sous-classe des objets gérés par NS
Utilisez l'éditeur de modèles de données de Xcode pour générer les fichiers de classe, ou les créer manuellement. Assurez-vous que votre entité utilise le réglage correct du module de classe.
3. Configurer la demande de prélèvement et la CRF
Dans votre contrôleur de vue, paramétrez la requête de récupération et initialisez le contrôleur de résultats récupérés. Il est préférable de le faire dans ou dans un modèle de vue init.
lazy var fetchedResultsController: NSFetchedResultsController<Task> = {
let fetchRequest: NSFetchRequest<Task> = Task.fetchRequest()
let sortDescriptor = NSSortDescriptor(key: "dueDate", ascending: true)
fetchRequest.sortDescriptors = [sortDescriptor]
// Optional: limit results with batch size for large datasets
fetchRequest.fetchBatchSize = 20
let controller = NSFetchedResultsController(
fetchRequest: fetchRequest,
managedObjectContext: PersistenceController.shared.container.viewContext,
sectionNameKeyPath: "completionStatus", // e.g., a transient attribute or a computed property
cacheName: nil
)
controller.delegate = self
try? controller.performFetch()
return controller
}()
4. Conduisez la vue de la table avec le FRC
Vos méthodes deviennent banales :
func numberOfSections(in tableView: UITableView) -> Int {
fetchedResultsController.sections?.count ?? 0
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let sectionInfo = fetchedResultsController.sections![section]
return sectionInfo.numberOfObjects
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TaskCell", for: indexPath)
let task = fetchedResultsController.object(at: indexPath)
configure(cell, with: task)
return cell
}
Notez que nous n'appelons jamais manuellement — les méthodes de délégation gèrent chaque insertion, suppression et mise à jour.
Utilisation avancée et pratiques exemplaires
Sécurité des fils
Les contextes de données de base ne sont pas sécurisés par les threads. Utilisez toujours le (qui fonctionne sur la file d'attente principale) pour toutes les requêtes de récupération et les CRF liées à l'interface utilisateur. Pour le travail de fond, créez un contexte de file d'attente privée et fusionnez les modifications au contexte de vue.
Cache
Le paramètre peut améliorer les performances de lancement en continuant à sectionner et à afficher des informations sur les objets. Cependant, si votre requête de recherche ou votre modèle de données change, vous devez supprimer le cache () pour éviter la corruption.
Gestion des ensembles de données de grande taille
Utilisez pour limiter le nombre d'objets récupérés dans la mémoire. Aussi, considérez le paramètre seulement si vous avez besoin d'un accès immédiat à chaque propriété. Pour les données à forte intensité de relation, pré-percevoir avec peut empêcher les erreurs répétées.
Intégration avec SwiftUI
Bien que soit centré sur l'UIKit, vous pouvez toujours l'utiliser dans SwiftUI en l'enveloppant dans un ou en utilisant le nouveau enveloppeur de propriété (qui utilise en interne un mécanisme similaire). Pour les données dynamiques complexes dans SwiftUI, est généralement suffisant, mais le FRC vous donne un contrôle fin sur les animations et les lots.
Pièges courants et comment les éviter
- Oubliant :[ Le contrôleur n'exécutera pas la récupération tant que vous n'avez pas appelé cette méthode. Faites-le une fois, habituellement juste après l'initialisation.
- Sans définir le délégué: Sans délégué, les changements ne se propagent pas à la vue de la table. Toujours appeler .
- Descripteurs de tri incorrects: Si le chemin de la touche nom de section ne correspond pas au descripteur de premier genre, des sections peuvent apparaître hors ordre. Assurez-vous que l'attribut utilisé dans apparaît dans les descripteurs de tri.
- L'utilisation aux côtés de FRC: Appeler pendant que le FRC anime les changements peut provoquer des accidents. Laissez les méthodes de délégation gérer toutes les mises à jour de l'interface utilisateur.
- Ignorer le contexte des données de base sauvegarde les échecs:[ Si vous enregistrez le contexte et qu'une erreur se produit, le FRC pourrait ne pas être informé.
Considérations relatives aux performances
est déjà efficace, mais voici des optimisations supplémentaires:
- Utilisez les prédicats avec sagesse:[ Un prédicat complexe peut ralentir la récupération initiale.Utilisez des attributs indexés lorsque c'est possible.
- Limiter les propriétés récupérées: Si vous avez seulement besoin de certains attributs, définissez sur la requête de récupération.
- Lorsque vous effectuez de nombreuses modifications, enveloppez-les dans un bloc pour réduire le nombre de rappels de délégués.
- Éviter les défauts inutiles:[ Si vous savez que vous accéderez à tous les objets dans un jeu de résultats, utilisez pour les pré-fetch, mais soyez prudent avec la mémoire.
Pour une plongée plus profonde dans les performances des données de base, voir Guide de performance des données de base d'Apple.
Exemples réels mondiaux
Exemple 1: Demande de clavardage
Une application de messagerie affiche une liste de conversations triées par le message le plus récent. De nouveaux messages entrants doivent apparaître instantanément. En utilisant un CRF, la vue contact peut s'abonner aux modifications uniquement pour les entités de conversation de l'utilisateur actuel.
Exemple 2 : Gestion des stocks
Une application e-commerce affiche les produits dans les catégories. Lorsque les niveaux de stock changent d'une synchronisation de fond, le FRC met automatiquement à jour l'interface utilisateur. En définissant à 50, la vue reste réactive même avec des milliers d'articles.
Exemple 3 : Liste à faire avec les catégories
L'exemple classique : les tâches regroupées en "Overdue", "Aujourd'hui" et "En venir". Le peut être un attribut dérivé transitoire calculé à partir de et de la date actuelle.
Conclusion
La maîtrise de la combinaison de Core Data et est une pierre angulaire de la construction d'applications iOS robustes et dynamiques. En déchargeant la lourde charge de suivi des changements et de synchronisation de l'interface utilisateur vers les cadres d'Apple, vous pouvez vous concentrer sur la création d'une expérience utilisateur formidable plutôt que d'écrire un code de gestion des données de la plaque de chaudière.
Que vous conserviez une application UIKit ou que vous adoptiez SwiftUI avec , les principes demeurent les mêmes : comprendre votre graphique d'objet, configurer soigneusement les requêtes de recherche et laisser le contrôleur de résultats récupéré faire ce qu'il fait de mieux. Avec les pratiques décrites dans cet article - y compris la mise en cache, la sécurité des fils et le réglage des performances - vous serez bien équipé pour gérer tout ensemble de données qui évolue au fil du temps.
Pour plus d'informations, consultez Le tutoriel de données de base de Ray Wenderlich et l'article [NSHipster] sur NSFetchedRésultatsContrôleur.