2012-04-12 7 views
5

ich Operationen in einer GCD Absende-Warteschlange auf einem NSManagedObjectContext folgendermaßen definiert tun:NSSortDescriptor von NSFetchRequest nicht nach Kontext Arbeits speichern

- (NSManagedObjectContext *)backgroundContext 
{ 
    if (backgroundContext == nil) { 
     self.backgroundContext = [NSManagedObjectContext MR_contextThatNotifiesDefaultContextOnMainThread]; 
    } 
    return backgroundContext; 
} 

MR_contextThatNotifiesDefaultContextOnMainThread ist eine Methode aus MagicalRecord:

NSManagedObjectContext *context = [[self alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; 
[context setParentContext:[NSManagedObjectContext MR_defaultContext]]; 
return context; 

Nach meine Objekte holen und ihnen die korrekte Schlangeposition geben ich log sie und die Reihenfolge ist korrekt. Das zweite Protokoll scheint jedoch völlig zufällig zu sein, der Sortierungsdeskriptor funktioniert eindeutig nicht.

Ich habe das Problem auf [self.backgroundContext save:&error] eingegrenzt. Nach dem Speichern des Hintergrundkontexts sind die Sortierdeskriptoren unterbrochen.

Ich habe keine Ahnung, warum der Sortierungsdeskriptor nicht funktioniert, wollen irgendwelche Kerndatenexperten helfen?

Update:

Das Problem tritt nicht auf iOS 4. Ich denke, der Grund, irgendwo zwischen Thread Isolation und privaten Warteschlange Modi in der Differenz ist. MagicalRecord verwendet automatisch das neue Concurrency-Muster, das sich unterschiedlich zu verhalten scheint.

Update 2:

Das Problem wurde gelöst Speichern des Hintergrundkontext durch eine Zugabe:

if ([[NSManagedObjectContext MR_contextForCurrentThread] hasChanges]) { 
    DLog(@"Changes"); 
    NSError *error = nil; 
    if ([[NSManagedObjectContext MR_contextForCurrentThread] save:&error] == NO) { 
     DLog(@"Error: %@", error); 
    } else { 
     NSManagedObjectContext *parent = [NSManagedObjectContext MR_contextForCurrentThread].parentContext; 
     [parent performBlockAndWait:^{ 
      NSError *error = nil; 
      if ([parent save:&error] == NO) { 
       DLog(@"Error saving parent context: %@", error); 
      } 
     }]; 
    } 
} 

Update 3:

MagicalRecord bietet eine Methode rekursiv speichern ein Kontext, jetzt sieht mein Code so aus:

if ([[NSManagedObjectContext MR_contextForCurrentThread] hasChanges]) { 
    DLog(@"Changes"); 
    [[NSManagedObjectContext MR_contextForCurrentThread] MR_saveWithErrorHandler:^(NSError *error) { 
     DLog(@"Error saving context: %@", error); 
    }]; 
} 

Schande über mich für ihn nicht in erster Linie mit ...

aber ich weiß nicht, warum dies hilft, und würde gerne eine Erklärung erhalten.

Antwort

2

Ich werde versuchen, zu kommentieren, da ich MagicalRecord schrieb.

Also, auf iOS5, MagicalRecord ist eingerichtet, um zu versuchen, die neue Private Queue-Methode von mehreren verwalteten Objektkontexten zu verwenden. Dies bedeutet, dass ein Speichervorgang im untergeordneten Kontext nur Sicherungen bis zum übergeordneten Element überträgt. Nur wenn ein Elternteil, der keine Eltern mehr hat, speichert, bleibt das Speichern in seinem Speicher bestehen. Dies ist wahrscheinlich in Ihrer Version von MagicalRecord passiert.

MagicalRecord hat versucht, dies für Sie in den späteren Versionen zu behandeln. Das heißt, es würde versuchen, zwischen dem privaten Warteschlangenmodus und dem Thread-Isolationsmodus zu wählen. Wie Sie herausgefunden haben, funktioniert das nicht so gut.Die einzige wirklich kompatible Möglichkeit zum Schreiben von Code (ohne komplexe Präprozessorregeln usw.) für iOS4 UND iOS5 ist die Verwendung des klassischen Thread-Isolationsmodus. MagicalRecord vom Tag 1.8.3 unterstützt dies und sollte für beide funktionieren. Ab 2.0 sind es nur private Warteschlangen von hier an.

Und wenn Sie in der MR_save-Methode schauen, werden Sie sehen, dass es auch die hasChanges-Prüfung für Sie durchführt (die möglicherweise auch nicht benötigt wird) Kerndaten Internals können das auch handhaben). Jedenfalls weniger Code, den Sie schreiben und pflegen sollten ...

+1

Vielen Dank für Ihre Eingabe, ich experimentierte noch mehr mit Thread-Isolation, aber ich würde lieber private Warteschlangen auf iOS 5 verwenden. Während des Testens denke ich, dass ich einen Fehler gefunden habe. Das Speichern des übergeordneten Kontexts wird für den Thread des untergeordneten Kontexts aufgerufen, was zu Problemen beim rekursiven Speichern aus einem GCD-Kontext führt. Ich habe eine Pull-Anfrage gesendet: https://github.com/magicalpanda/MagicalRecord/pull/159 – tim

-2

Da CoreData kein Safe-Thread-Framework ist und für jeden Thread (Operationswarteschlange) Core-Daten unterschiedliche Kontexte verwenden. Bitte beachten Sie die folgenden ausgezeichneten Schreiben

http://www.duckrowing.com/2010/03/11/using-core-data-on-multiple-threads/

+0

Der backgroundContext wird aus dem GCD-Block initialisiert und kein ManagedObject oder ManagedObjectContext überschreitet Thread-Grenzen, also glaube ich nicht, dass das mein Problem hier ist. – tim

1

Der eigentliche Grund, warum Ihre ursprüngliche Einrichtung nicht funktionierte, ist ein Apple-Fehler beim Abrufen aus einem Kindkontext mit Sortierdeskriptoren, wenn der Elternkontext noch nicht vorhanden ist gespeichert zu speichern:

NSSortdescriptor ineffective on fetch result from NSManagedContext

Wenn es eine Möglichkeit ist, dass Sie verschachtelten Kontexten vermeiden können, sie tun zu vermeiden, da sie mit den vermeintlichen Leistungsgewinne werden enttäuscht noch sehr buggy und Sie werden wahrscheinlich sind, vgl auch: http://wbyoung.tumblr.com/post/27851725562/core-data-growing-pains

Verwandte Themen