2010-12-01 13 views
3

J'utilise NSFetchedResultsController avec un UITableView qui affiche une liste de dossiers et de décomptes non lus associés pour chaque élément de ce dossier. Je voudrais insérer/supprimer des dossiers w/animation de la tableView en fonction du nombre non lu lors d'une synchronisation/actualisation (sur un thread d'arrière-plan en utilisant NSManagedObjectContextDidSaveNotification). Les dossiers sans éléments non lus doivent disparaître, et les dossiers existants avec de nouveaux éléments non lus devraient disparaître dans.Mise à jour/Insertion d'objets existants dans NSFetchedResultsController

actuellement en utilisant la méthode controller:didChangeObject:atIndexPath:forChangeType:newIndexPath: ne le fait pas à moins que le tableView est complètement rechargée, ou l'application est relancée, ce qui est idéal .

Est-ce que le NSFetchedResultsController n'est pas le moyen de le faire? Mon idée initiale était de créer une entité de base de données séparée qui ne contient que les dossiers avec des éléments non lus, et d'ajouter/supprimer des dossiers de cela, mais cela semble juste hokey.

Mon NSPredicate ressemble à quelque chose comme:

ANY items.unread == 1

Mise à jour: ci-dessus NSPredicate fonctionne très bien et saisit les objets que j'attendez. Mon problème est que si l'application se lance et que FolderX a 0 élément non lu, il n'apparaît pas. Si je puis actualiser (sort et analyse un fichier JSON dans un thread d'arrière-plan) et FolderX a maintenant 25 éléments non lus, il pas automatiquement fondu ou déclencher NSFetchedResultsChangeInsert et comme il n'a pas été inclus en premier lieu, il ne déclenche pas NSFetchedResultsChangeUpdate ce qui explique pourquoi je pensais que la solution était de créer une entité distincte qui ne contient que des dossiers avec des éléments non lus et ajouter/supprimer de cela pendant la synchronisation. J'ai juste l'impression de manquer quelque chose de douloureusement évident.

Mise à jour 2: J'ai simplifié le problème autant que possible en supprimant l'influence de mon application, je suis capable de le reproduire dans le modèle par défaut de base de données dans Xcode. Le nouveau problème: Il existe une seule entité nommée "Evénement" sans relation et deux propriétés, "Date" et "unreadCount". Je NSFetchedResultsController mis en place avec un NSPredicate qui ressemble à:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"unreadCount < 10"]; 

Chaque fois qu'un nouvel objet est ajouté, il est créé avec un unreadCount de 15 ans, puis tous les objets existants sont décrémentés par 1. Cela se fait sur une séparé ManagedObjectContext (pour répliquer le traitement en arrière-plan, mais tout est fait sur le thread principal). J'ai implémenté le controllerWillChangeContent et les méthodes associées, et ce que je m'attendais à ce que ce soit après qu'un objet existant (avec unreadCount de 15) soit décrémenté 5 fois (pour être maintenant 10) il devrait être inséré dans la tableView parce que il correspond maintenant au prédicat. Ce n'est pas du tout ce qui se passe, l'objet n'apparaît pas du tout sauf si l'application est redémarrée.

J'ai joint un exemple de projet, lancez-le simplement et cliquez plusieurs fois sur le bouton Ajouter (rien ne se passera). Redémarrez l'application et vous verrez une poignée d'objets maintenant dans la tableView, si vous cliquez sur le bouton Ajouter quelques fois plus ces objets seront supprimés, mais les nouveaux objets ne seront pas ajoutés.

Si NSFetchedResultsController n'est pas la solution pour que ce comportement fonctionne, alors qu'est-ce?

Exemple de projet: http://dl.dropbox.com/u/521075/BGUpdating.zip

+0

Quelle était votre solution à ce problème? Parce que j'ai une question similaire: http://stackoverflow.com/questions/12776371/gmgridview-with-nsfetchedresultscontroller-data-not-updating-reloading – acecapades

Répondre

1

Votre prédicat ne fonctionnera pas traverser deux ou plusieurs à-plusieurs. Vous avez actuellement:

type == folder AND ANY (set of folders).(set of items).unread == 1 

Vous ne pouvez pas utiliser ANY pour traverser un nombre arbitraire de relations. Au lieu de cela, vous avez probablement besoin d'un subquery comme:

type == folder AND (0!=SUBQUERY(folder,$f,0!=SUBQUERY($f.items,$i,$i.unread==1)[email protected])[email protected]) 

Je pense que vous peut-être effectuer l'opération d'extraction sur la mauvaise entité. Si vous présentez une table de Folder objets, vous devez effectuer l'extraction sur l'entité Folder. Cela seul permettrait de tout simplifier. Votre prédicat serait alors juste:

ANY items.unread==1 
+0

J'ai mis à jour ma question pour être un peu plus simple et clair, et aussi supprimé la relation to-many et récupérant l'entité Folder directement mais n'obtenant toujours pas les résultats attendus. – kaptin

+0

Le problème semble alors être avec la notification suivant la fusion. La fusion doit déclencher la FRC pour informer son délégué que quelque chose a changé. Assurez-vous que les relations inverses sont définies dans le modèle de données afin qu'une modification dans l'objet Dossier ou Élément soit répercutée de l'autre côté de la relation. – TechZen

+0

Merci pour l'aide, j'ai creusé un peu plus profond et encore une fois mis à jour ma question pour être encore plus précis en supprimant l'influence de mon propre modèle d'application. – kaptin