Jednoczesne i niezawodne korzystanie z podstawowych danych

Buduję swoją pierwszą aplikację na system iOS, która teoretycznie powinna być całkiem prosta, ale mam trudności z uczynieniem jej wystarczająco kuloodporną, aby czuć się pewnie przesyłając ją do App Store.

W skrócie, główny ekran ma widok tabeli, po wybraniu wiersza wskazuje na inny widok tabeli, który wyświetla informacje istotne dla wybranego wiersza w sposób mistrzowsko-szczegółowy. Dane podstawowe są pobierane jako dane JSON z usługi internetowej raz dziennie, a następnie buforowane w magazynie danych podstawowych. Dane poprzedzające ten dzień są usuwane, aby uniemożliwić nieograniczony rozwój pliku bazy danych SQLite. Wszystkie operacje utrwalania danych są wykonywane przy użyciu danych podstawowych, za pomocąNSFetchedResultsController podstawa widoku tabeli szczegółów.

Problem, który widzę, polega na tym, że jeśli kilka razy szybko przełączasz się między ekranami głównym i szczegółowym, podczas gdy świeże dane są pobierane, analizowane i zapisywane, aplikacja całkowicie zawiesza się lub zawiesza. Wydaje się, że istnieje jakiś rodzaj wyścigu, może z powodu importowania danych Core Data w tle, podczas gdy główny wątek próbuje wykonać pobieranie, ale spekuluję. Miałem problem z przechwyceniem jakichkolwiek znaczących informacji o awariach, zazwyczaj jest to SIGSEGV głęboko w stosie danych podstawowych.

Poniższa tabela pokazuje rzeczywistą kolejność zdarzeń, które mają miejsce, gdy załadowany jest kontroler widoku tabeli szczegółów:

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

Po wyzwoleniu bloku zakończenia AFNetworking, gdy nadejdą dane JSON, zagnieżdżonyNSManagedObjectContext jest tworzony i przekazywany do obiektu „importera”, który analizuje dane JSON i zapisuje obiekty w magazynie danych podstawowych. Importer wykonuje za pomocą nowegoperformBlock metoda wprowadzona w iOS 5:

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

Obiekt importera obserwuje własne MOCNSManagedObjectContextDidSaveNotification a następnie publikuje własne powiadomienie obserwowane przez kontroler widoku tabeli szczegółów. Gdy to powiadomienie jest zaksięgowane, kontroler widoku tabeli wykonuje własny zapis (MOC).

Używam tego samego podstawowego wzoru z obiektem „deleter” do usuwania starych danych po zaimportowaniu nowych danych na dany dzień. Dzieje się to asynchronicznie po pobraniu nowych danych przez pobrany kontroler wyników, a widok tabeli szczegółów został ponownie załadowany.

Jedną rzeczą, której nie robię, jest obserwowanie wszelkich powiadomień o scalaniu lub blokowanie dowolnych kontekstów obiektów zarządzanych lub koordynatora trwałego sklepu. Czy powinienem to robić? Nie jestem pewien, jak poprawnie to zaprojektować, więc byłbym wdzięczny za każdą radę.

questionAnswers(4)

yourAnswerToTheQuestion