Core-Daten gleichzeitig und zuverlässig nutzen

Ich erstelle meine erste iOS-App, die theoretisch recht unkompliziert sein sollte, aber ich habe Schwierigkeiten, sie so kugelsicher zu machen, dass ich mich sicher fühle, sie beim App Store einzureichen.

Kurz gesagt, der Hauptbildschirm verfügt über eine Tabellenansicht. Nach Auswahl einer Zeile wird eine andere Tabellenansicht aufgerufen, in der die für die ausgewählte Zeile relevanten Informationen in einer Master-Detail-Weise angezeigt werden. Die zugrunde liegenden Daten werden einmal täglich als JSON-Daten von einem Webdienst abgerufen und dann in einem Core Data Store zwischengespeichert. Die Daten vor diesem Tag werden gelöscht, um ein unbegrenztes Anwachsen der SQLite-Datenbankdatei zu verhindern. Alle Datenpersistenzoperationen werden unter Verwendung von Kerndaten mit einem ausgeführtNSFetchedResultsController Unterstützt die Detailtabellenansicht.

Das Problem, das ich sehe, ist, dass, wenn Sie mehrmals schnell zwischen dem Master- und Detailbild wechseln, während frische Daten abgerufen, analysiert und gespeichert werden, die App einfriert oder vollständig abstürzt. Es scheint eine Art Racebedingung zu geben, möglicherweise weil Core Data Daten im Hintergrund importiert, während der Hauptthread versucht, einen Abruf durchzuführen, aber ich spekuliere. Ich hatte Probleme, wichtige Absturzinformationen zu erfassen. Normalerweise handelt es sich um ein SIGSEGV, das sich tief im Core Data-Stack befindet.

Die folgende Tabelle zeigt die tatsächliche Reihenfolge der Ereignisse, die auftreten, wenn der Controller für die Detailtabellenansicht geladen wird:

Main Thread                          Background Thread
viewDidLoad

                                     Get JSON data (using AFNetworking)

Create child NSManagedObjectContext (MOC)

                                     Parse JSON data
                                     Insert managed objects in child MOC
                                     Save child MOC
                                     Post import completion notification

Receive import completion notification
Save parent MOC
Perform fetch and reload table view

                                     Delete old managed objects in child MOC
                                     Save child MOC
                                     Post deletion completion notification

Receive deletion completion notification
Save parent MOC

Sobald der AFNetworking-Abschlussblock ausgelöst wird, wenn die JSON-Daten eingetroffen sind, wird er verschachteltNSManagedObjectContext wird erstellt und an ein "Importer" -Objekt übergeben, das die JSON-Daten analysiert und die Objekte im Core-Datenspeicher speichert. Der Importeur führt das Neue ausperformBlock In iOS 5 eingeführte Methode:

NSManagedObjectContext *child = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    [child setParentContext:self.managedObjectContext];        
    [child performBlock:^{
        // Create importer instance, passing it the child MOC...
    }];

Das Importobjekt beobachtet seine eigenen MOCsNSManagedObjectContextDidSaveNotification und sendet dann eine eigene Benachrichtigung, die von der Steuerung für die Detailtabellenansicht überwacht wird. Wenn diese Benachrichtigung gesendet wird, führt der Table View Controller eine Sicherung für seinen eigenen (übergeordneten) MOC durch.

Ich verwende das gleiche Grundmuster mit einem "Deleter" -Objekt zum Löschen der alten Daten, nachdem die neuen Daten für den Tag importiert wurden. Dies geschieht asynchron, nachdem die neuen Daten vom Controller für abgerufene Ergebnisse abgerufen und die Detailtabellenansicht erneut geladen wurden.

Eine Sache, die ich nicht tue, ist das Beobachten von Zusammenführungsbenachrichtigungen oder das Sperren von verwalteten Objektkontexten oder des beständigen Geschäftskoordinators. Sollte ich das tun? Ich bin ein bisschen unsicher, wie ich das alles richtig konstruieren soll, also würde ich mich über Ratschläge freuen.

Antworten auf die Frage(4)

Ihre Antwort auf die Frage