[Résolu] Core Data beginUndoGrouping / endUndoGrouping: j'ai dû mal comprendre...
Bonjour,
Dans une NSTableView, j'offre la possibilité d'ajouter, de retirer et de réordonnancer les colonnes. Chaque NSTableColumn possède une référence à l'entité Core Data "Column" stockée dans sa headerCell.representedObject.
L'entité elle-même possède un attribut "rank" qui mémorise la position de la colonne dans la tableView.
De fait, tout cela fonctionne parfaitement... jusqu'au "undo", qui est réglé dans l'entité Column:
- (void) awakeFromSnapshotEvents:(NSSnapshotEventType)flags
{
[super awakeFromSnapshotEvents:flags];
[[NSNotificationCenter defaultCenter] postNotificationName:@ColumnModification object:self userInfo:[NSDictionary dictionaryWithObject:@(flags) forKey:@flags ]];
}
Si j'ajoute au retire une colonne, si je change son titre, le undo fait son travail. Le problème survient au undo d'un déplacement de colonne.
Il est impossible de ne changer le rang que d'une colonne: le rang des autres est forcément modifié aussi. Je renumérote donc toutes les entités à chaque changement de colonne, mais comme je veux qu'un seul undo rétablisse l'ordre initial, je groupe les modifications, comme ceci:
- (void)tableViewColumnDidMove:(NSNotification *)aNotification
{
[[self.managedObjectContext undoManager] beginUndoGrouping];
for (long rank =0; rank<self.tableview.tableColumns.count; rank++)
{
NSTableColumn *tableColumn = self.tableview.tableColumns[rank];
[(Column *)tableColumn.headerCell.representedObject setRank:rank];
}
[[self.managedObjectContext undoManager] endUndoGrouping];
}
Mais le undo ne se comporte pas comme prévu: j'entre dans une boucle sans fin, et le contrôleur réinsère les objets, la fonction awakeFromSnapshotEvents est appelée, qui lance une notification"columnModification", puis le contrôleur réinsère les objets, etc...
- (void) columnModification: (NSNotification*)notification
{
{
while (self.tableview.tableColumns.count>0) {
[self.tableview removeTableColumn:self.tableview.tableColumns[0]];
}
[self prepareContent];
[self.tableview reloadData];
}
}
Qu'est-ce que j'ai encore manqué?
Réponses
Note aussi que si je ne me trompe pas, annuler ne va pas replacer les colonnes, puisque ça va juste changer le "rank" interne.
Sinon, sache que la gestion de l'undo par Core Data est abominable. J'avais essayé de logger les écritures dans l'undo manager, mais il fait son bricolage interne, c'est indébuggable, et ça ne fonctionne pas en test unitaire.
Voir aussi ici:
http://mikeabdullah.net/core_data_undo_management.html
http://blog.wilshipley.com/2007/12/transitions-and-epiphanies.html
Bonjour Céroce,
Oui, j'utilise NSManagedDocument, et le ColumnController à un outlet sur son contexte. Le undoManager est le même, j'ai vérifié.
Non, le undo ne va pas replacer les colonnes, voila pourquoi je:
- supprime toutes les colonnes (les NSTableColumns, pas les entités)
- les recrée dans le "prépareContent" du contrôleur.
D'ailleurs, le undo fonctionne parfaitement pour ADD, REMOVE et RESIZE.
Voici les deux routines qui sont appelées à tour de rôle, sans fin:
et
Je n'y comprends rien. On dirait que awakeFromSnapshotEvents est appelée sans nécessité...
EDIT:
Ooops... je crois que j'ai trouvé... c'est:
qui rajoutait un observateur... qui recevait le message de modification... qui rajoutait l'observateur.