CoreData und die iCloud- Crashes

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • CoreData und die iCloud- Crashes

    Hallo und willkommen im frischen Look,

    mein erster Kontakt zu CoreData liegt vielleicht zwei Wochen zurück, der Einstieg ging schnell, ich komme gut damit zurecht. Ich hatte es vorher nie mit Programmierung von Apps zu tun, die persistent etwas speichern sollten, bis vor einiger Zeit. Mit dem optimistischen Hintergedanken, dass durch CoreData ja auch der iCloud-Sync praktisch automatisch funktioniert… Ha.

    Ich bin jetzt soweit, dass der Sync an und für sich eigentlich im Großen und Ganzen funktioniert (soweit es iCloud eben hergibt). Als API-Klasse benutze ich den hier: github.com/lhunath/UbiquityStoreManager
    Mit dem Ding habe ich bloß ein kleines Problem und ein großes Problem, aber fangen wir mit dem Großen an:
    Das Löschen von Entitäten auf Gerät A wird vorgenommen, funktioniert. Der Sync kommt auf Gerät B, C und D, die Apps sehen die Änderungen und stürzen ab.
    Bei Änderungen oder Einfügungen von Entitäten tritt dieses Problem nicht auf.

    Jetzt etwas konkreter, das ist Code aus der API-Klasse:

    Quellcode

    1. - (void)didImportChanges:(NSNotification *)note {
    2. NSManagedObjectContext *moc = nil;
    3. if ([self.delegate respondsToSelector:@selector(ubiquityStoreManager:managedObjectContextForUbiquityChanges:)])
    4. moc = [self.delegate ubiquityStoreManager:self managedObjectContextForUbiquityChanges:note];
    5. if (moc) {
    6. [self log:@"Importing ubiquity changes into application's MOC. Changes:\n%@", note.userInfo];
    7. [moc performBlockAndWait:^{
    8. [moc mergeChangesFromContextDidSaveNotification:note];
    9. NSError *error = nil;
    10. if ([moc hasChanges] && ![moc save:&error]) {
    11. [self error:error cause:UbiquityStoreErrorCauseImportChanges context:note];
    12. [self reloadStore];
    13. return;
    14. }
    15. }];
    16. }
    17. else
    18. [self log:@"Application did not specify an import MOC, not importing ubiquity changes:\n%@", note.userInfo];
    19. dispatch_async( dispatch_get_main_queue(), ^{
    20. [[NSNotificationCenter defaultCenter] postNotificationName:USMStoreDidImportChangesNotification
    21. object:self userInfo:[note userInfo]];
    22. } );
    23. }
    Alles anzeigen


    In der Zeile 14 (hier im Code oben), passiert der Crash. Leider bekomme ich keinen genauen Hinweis, was da jetzt genau gecrasht ist (In der Konsole findet sich nur ein »(lldb)«).
    Mache ich zwei Mal 'Continue Execution' läuft die App nämlich genau richtig weiter und entfernt den Datensatz aus dem TableView.
    Mir ist natürlich klar, dass der Crash nicht am Code der API-Klasse liegt, sondern an meinem Code.

    Also kommen wir zum TableView, der diese Änderung entgegennehmen soll (ich habe bisher alle anderen Observer auskommentiert im gesamten Code):

    Quellcode

    1. - (void)setUpCoreDataObserver
    2. {
    3. JGAppDelegate *appDelegate = [JGAppDelegate sharedAppDelegate];
    4. NSManagedObjectContext *context = [appDelegate managedObjectContext];
    5. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleDataModelChange:) name:NSManagedObjectContextObjectsDidChangeNotification object:context];
    6. // STEP 3 - Handle USMStoreDidChangeNotification to update the UI.
    7. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resetUI) name:USMStoreWillChangeNotification object:[JGAppDelegate sharedAppDelegate].ubiquityStoreManager];
    8. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleDataModelChange:) name:USMStoreDidChangeNotification object:[JGAppDelegate sharedAppDelegate].ubiquityStoreManager];
    9. }
    Alles anzeigen


    Dieser Code wird in initWithStyle: ausgeführt. Der folgende Code wird ausgeführt, wenn die USMStoreDidChangeNotification reinkommt:

    Quellcode

    1. - (void)handleDataModelChange:(NSNotification *)note
    2. {
    3. NSLog(@"handle model change: %@",note);
    4. NSSet *deletedObjects = [[note userInfo] objectForKey:NSDeletedObjectsKey];
    5. NSSet *insertedObjects = [[note userInfo] objectForKey:NSInsertedObjectsKey];
    6. if (self.isViewLoaded && self.view.window && deletedObjects.count == 1 && [deletedObjects containsObject:self.swipeDeletedPurchase])
    7. {
    8. // do nothing, just a deletion by swipe-to delete
    9. }
    10. else if (insertedObjects.count > 0)
    11. {
    12. for (NSObject *obj in insertedObjects)
    13. {
    14. if ([obj isKindOfClass:[JGPurchase class]])
    15. {
    16. [self animateInsertion:(JGPurchase *)obj];
    17. }
    18. }
    19. }
    20. else if (deletedObjects.count > 0)
    21. {
    22. for (NSObject *obj in deletedObjects)
    23. {
    24. if ([obj isKindOfClass:[JGPurchase class]])
    25. {
    26. [self.purchases removeObject:(JGPurchase *)obj];
    27. [self.tableView reloadData];
    28. }
    29. }
    30. }
    31. else
    32. {
    33. [self loadData];
    34. }
    35. }
    Alles anzeigen


    Dieser Code wird ausgeführt, wenn die Änderung ankommt. Funktioniert im Normalfall auch klasse, nur nicht beim Löschen. Da wird dann plötzlich loadData: (Zeile 35) ausgeführt, statt der Lösch-Schleife, warum? Keine Ahnung. Das Problem tritt dann in der Methode loadData: auf, wenn diese Methode hier aufgerufen wird:

    Quellcode

    1. - (NSArray *)loadAllPurchases
    2. {
    3. JGAppDelegate *appDelegate = [JGAppDelegate sharedAppDelegate];
    4. NSManagedObjectContext *context = [appDelegate managedObjectContext];
    5. if (context != nil)
    6. {
    7. __block NSArray *objects;
    8. [context performBlockAndWait:^
    9. {
    10. NSEntityDescription *entityDesc = [NSEntityDescription entityForName:@"Purchase" inManagedObjectContext:context];
    11. NSFetchRequest *request = [[NSFetchRequest alloc] init];
    12. [request setEntity:entityDesc];
    13. NSError *error;
    14. objects = [context executeFetchRequest:request error:&error];
    15. if (error)
    16. {
    17. NSLog(@"err: %@",error);
    18. }
    19. }];
    20. return objects;
    21. }
    22. return nil;
    23. }
    Alles anzeigen


    Genauer gesagt in Zeile 18, wenn executeFetchRequest: ausgeführt wird. Kommentiere ich diese Zeile aus, kommt es nicht zum Crash.

    Um mal ein Fazit zu ziehen: Ich habe mir viel Mühe gegeben, das hier etwas sortiert aufzuschreiben aber selbst den Überblick verloren, wo wann und was jetzt warum zu Fehlern führt. Auch habe ich mittlerer Weile auf allen möglichen Geräten verschiedene Builds laufen, um den Fehler genauer zu entdecken, jedoch habe ich es auch versucht, iCloud-Daten zu löschen und alle Apps zu löschen. Das Problem besteht weiterhin.
    Ich denke, dass es sicherlich nichts Offensichtliches ist sondern MemoryManagement? Liegt's an den Observern? Die werden natürlich in dealloc entfernt.

    Hat irgendjemand Hinweise? Ich komm da nicht mehr so ganz klar.

    Vielen Dank fürs Lesen.

    Liebe Grüße
    Jan


    UPDATE:
    Ich bin irgendwie verwirrt, mache ich All-ObjC-Exceptions aus, läuft das Ding genau richtig weiter. Was habe ich da falsch verstanden?

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von rosi-janni ()