Ich stieß auf merkwürdiges Verhalten, wenn NSManagedObjectContext 's performBlock:
mit Benachrichtigungszentrale verwendet.NSManagedObjectContext: performBlockAndWait vs performBlock mit Benachrichtigungszentrale
Vom Haupt-UI-Thread ich Trigger asynchronen Daten herunterladen (mit NSURLConnectionconnectionWithRequest:
). Wenn die Daten der folgenden Delegatmethode ankommen heißt:
- (void)downloadCompleted:(NSData *)data
{
NSArray *new_data = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
self.backgroundObjectContext = [[NSManagedObjectContext alloc]
initWithConcurrencyType:NSPrivateQueueConcurrencyType];
self.backgroundObjectContext.persistentStoreCoordinator = self.persistentStoreCoordinator;
[self.backgroundObjectContext performBlockAndWait:^{
[self saveToCoreData:new_data];
}];
}
Die savetoCoreData:
Methode einfach neue Daten in den Hintergrund Kontext zu speichern:
- (void)saveToCoreData:(NSArray*)questionsArray
{
for (NSDictionary *questionDictionaryObject in questionsArray) {
Question *newQuestion = [NSEntityDescription
insertNewObjectForEntityForName:@"Question"
inManagedObjectContext:self.backgroundObjectContext];
newQuestion.content = [questionDictionaryObject objectForKey:@"content"];
}
NSError *savingError = nil;
[self.backgroundObjectContext save:&savingError];
}
Im View-Controller, in viewDidLoad
ich hinzufügen Beobachter auf die Benachrichtigung Zentrum:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contextChanged:)
name:NSManagedObjectContextDidSaveNotification
object:nil];
Und dann in den contexChanged:
ich den Hintergrund Zusammenhang mit dem Haupt Kontext verschmelzen so tha t sind meine NSFetchedResultsController der Delegatmethoden genannt, wo meine Ansicht aktualisiert werden kann:
- (void)contextChanged:(NSNotification*)notification
{
if ([notification object] == self.managedObjectContext) return;
[self.managedObjectContext mergeChangesFromContextDidSaveNotification:notification];
}
Es scheint alles gut zu funktionieren, aber es gibt eine Sache, die mich stört. Wenn in downloadCompleted:
Methode verwende ich performBlock:
anstelle von performBlockAndWait:
die Benachrichtigung scheint sich zu verzögern. Es dauert bemerkenswerte (ca. 5s) Zeit von dem Moment an, in dem der Hintergrund-Thread save:
bis zu dem Moment NSFetchedResultsController Aufrufe seiner Stellvertretung. Wenn ich performBlockAndWait:
verwende, beobachte ich keine sichtbare Verzögerung - der Delegierte wird so schnell aufgerufen, als ob ich saveToCoreData:
innerhalb _dispatch_async_
angerufen hätte.
Hat jemand das vorher gesehen und weiß, ob das normal ist oder missbrauche ich etwas?
Beachten Sie, dass die Benachrichtigung für den Hintergrundthread ausgelöst wird und Sie Änderungen an den Hauptkontext in einem Hintergrundthread zusammenführen, was sehr schlecht ratsam ist. Verwenden Sie '[self.managedObjectContext performBlockAndWait: ...]' –
Das ist in der Tat vollkommen sinnvoll. Danke Dan! Ich habe nicht erkannt, dass 'connectionWithRequest:' die Delegate-Methoden für "(...) den Thread aufruft, der den asynchronen Ladevorgang für das verknüpfte NSURLConnection-Objekt gestartet hat." Dies kann leicht durch Überprüfen von '[NSThread isMainThread]' beobachtet werden. –