Vor kurzem habe ich angefangen, für Xebia zu arbeiten, und wie könnte ich mich besser vorstellen als mit einem netten Blogpost und etwas kostenlosem Code und einigen Erklärungen dazu. Für den Anfang: hier ist der Code. Er befindet sich auf GitHub, also scheuen Sie sich nicht, Vorschläge und Ähnliches einzubringen.Das Beispiel, über das ich heute sprechen werde, ist größtenteils in diesen Klassen enthalten:
- XSDAppDelegate
- XSDFirstViewController
Stellen Sie einfach sicher, dass Sie den Quellcode ein wenig durchstöbern, bevor Sie Fragen stellen. ;) Das folgende Bild sollte Ihnen einen allgemeinen Überblick darüber geben, wie das Beispiel funktioniert.
Nun zu den interessanten Teilen. Wie Sie in der Abbildung sehen können, nutzt das Beispiel eine Reihe von Mechanismen, die im iOS-Framework verfügbar sind. Diese sind CoreData, NSOperation, NSFetchedResultsController und Notification Center.
Der NSFetchedResultsController führt eine Abrufanfrage an den CoreData-Speicher durch. Alle Änderungen, die den NSManagedObjectContext des NSFetchedResultsControllers betreffen, werden aufgegriffen und an den XSDFirstViewController delegiert. Der XSDFirstViewController implementiert das NSFetchedResultsControllerDelegate Protokoll.
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller { //Lässt den Tableview wissen, dass wir möglicherweise eine Reihe von Aktualisierungen vornehmen. [self.tableView beginUpdates]; }
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller { //Wir sind fertig mit der Aktualisierung der Daten des Tableviews. [self.tableView endUpdates]; }
- (void)controller:(NSFetchedResultsController )controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath )indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath )newIndexPath { UITableView tableView = self.tableView; switch(typ) { case NSFetchedResultsChangeInsert: [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; Pause; case NSFetchedResultsChangeDelete: [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; Pause; case NSFetchedResultsChangeUpdate: [tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; Pause; case NSFetchedResultsChangeMove: [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; Pause; } }
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
switch(type) {
case NSFetchedResultsChangeInsert:
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
[/sourcecode]
Die NSOperation-Unterklasse XSDSyncOperation definiert die Hintergrundarbeit, die den Inhalt des CoreDate-Speichers ändert. Wichtig ist, dass die XSDSyncOperation ihren eigenen NSManagedObjectContext erhält, der denselben NSPersistentStoreCoordinator verwendet wie der vom NSFetchedResultsController verwendete Kontext. (Lesen Sie die letzte Zeile noch einmal und vergewissern Sie sich, dass Sie verstanden haben, was ich sage.)
Ein NSPersistentStoreCoordinator kann von mehreren Threads gemeinsam genutzt werden, ein NSManagedObjectContext nicht. Lesen Sie das CoreData Programmierhandbuch, um mehr darüber zu erfahren.
Wenn nun die XSDSyncOperation etwas im CoreDate-Speicher speichert, muss der andere Kontext über diese Änderung informiert werden. Und hier kommt der folgende Codeschnipsel ins Spiel, der Teil der XSDSyncOperation ist. [sourcecode language="c"] //Ergebene Objekte speichern und den Speichervorgang an das SyncDelegate senden. [[NSNotificationCenter defaultCenter] addObserver:syncDelegate selector:@selector(syncDidSave:) name:NSManagedObjectContextDidSaveNotification object:context]; [context save:&error]; [[NSNotificationCenter defaultCenter] removeObserver:syncDelegate name:NSManagedObjectContextDidSaveNotification object:context]; [/sourcecode] An dem obigen Ausschnitt gibt es einige Dinge zu beachten. Erstens ist die NSManagedObjectContextDidSaveNotification eine Benachrichtigung, die jeder NSManagedObjectContext aussendet, wenn er eine Speichernachricht erhält. Zweitens, der Beobachter syncDelegate mit dem Selektor syncDidSave:. Der XSDAppDelegate implementiert ein Protokoll namens XSDSyncDelegate. Dieses Protokoll definiert die syncDidSave: Nachricht. Wenn also die XSDSyncOperation ihren Kontext speichert, wird eine Nachricht syncDidSave: auf dem XSDAppDelegate mit einem Parameter aufgerufen, der NSManagedObjectContextDidSaveNotification, die durch die ursprüngliche Speichernachricht für den Kontext der XSDSyncOperation ausgelöst wurde. Hier ist die Implementierung der syncDidSave: Methode auf dem XSDAppDelegate: [sourcecode language="c"] - (void)syncDidSave:(NSNotification *)saveNotification { if ([NSThread isMainThread]) { [self.managedObjectContext mergeChangesFromContextDidSaveNotification:saveNotification]; } else { [self performSelectorOnMainThread:@selector(syncDidSave:) withObject:saveNotification waitUntilDone:NO]; } } [/sourcecode] Hier ist ein wenig Logik im Spiel, um die Verarbeitung auf den Hauptthread zu verlagern. Sobald wir im Haupt-Thread sind, wird die Benachrichtigung "in den Kontext des Haupt-Threads integriert". Und voilà, der Kontext ändert sich, der NSFetchedResultController nimmt sie auf und die Benutzeroberfläche wird aktualisiert.
Verfasst von

Jeroen Leenarts
Contact



