Best Practice im Kontext des Core Data-Hintergrunds

Ich habe eine große Importaufgabe, die ich mit Kerndaten erledigen muss.
Angenommen, mein Kerndatenmodell sieht folgendermaßen aus:

Car
----
identifier 
type

Ich hole eine Liste von Auto-Info-JSON von meinem Server und möchte sie dann mit meinen Kerndaten synchronisierenCar Objekt, was bedeutet:
Wenn es ein neues Auto ist -> erstelle ein neues Core DataCar Objekt aus der neuen Info.
Wenn das Auto bereits existiert -> aktualisieren Sie die Core-DatenCar Objekt.

Daher möchte ich diesen Import im Hintergrund ausführen, ohne die Benutzeroberfläche zu blockieren, und während der Verwendung eine Autos-Tabellenansicht scrollen, in der alle Autos angezeigt werden.

Momentan mache ich so etwas:

// create background context
NSManagedObjectContext *bgContext = [[NSManagedObjectContext alloc]initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[bgContext setParentContext:self.mainContext];

[bgContext performBlock:^{
    NSArray *newCarsInfo = [self fetchNewCarInfoFromServer]; 

    // import the new data to Core Data...
    // I'm trying to do an efficient import here,
    // with few fetches as I can, and in batches
    for (... num of batches ...) {

        // do batch import...

        // save bg context in the end of each batch
        [bgContext save:&error];
    }

    // when all import batches are over I call save on the main context

    // save
    NSError *error = nil;
    [self.mainContext save:&error];
}];

Aber ich bin mir nicht sicher, ob ich hier das Richtige tue, zum Beispiel:

Ist es in Ordnung, dass ich benutzesetParentContext ?
Ich habe einige Beispiele gesehen, die es so verwenden, aber ich habe andere Beispiele gesehen, die es nicht nennensetParentContextstattdessen machen sie so etwas:

NSManagedObjectContext *bgContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
bgContext.persistentStoreCoordinator = self.mainContext.persistentStoreCoordinator;  
bgContext.undoManager = nil;

Eine andere Sache, bei der ich nicht sicher bin, wann ich save im Hauptkontext aufrufen soll. In meinem Beispiel habe ich save am Ende des Imports aufgerufen, aber ich habe Beispiele gesehen, die Folgendes verwenden:

[[NSNotificationCenter defaultCenter] addObserverForName:NSManagedObjectContextDidSaveNotification object:nil queue:nil usingBlock:^(NSNotification* note) {
    NSManagedObjectContext *moc = self.managedObjectContext;
    if (note.object != moc) {
        [moc performBlock:^(){
            [moc mergeChangesFromContextDidSaveNotification:note];
        }];
    }
}];  

Wie ich bereits erwähnt habe, möchte ich, dass der Benutzer während der Aktualisierung mit den Daten interagieren kann. Was ist also sicher, wenn der Benutzer einen Fahrzeugtyp ändert, während der Import dasselbe Fahrzeug ändert?

AKTUALISIEREN:

Dank der großartigen Erklärung von @TheBasicMind versuche ich, Option A zu implementieren, sodass mein Code ungefähr so aussieht:

Dies ist die Core Data-Konfiguration in AppDelegate:

AppDelegate.m  

#pragma mark - Core Data stack

- (void)saveContext {
    NSError *error = nil;
    NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
    if (managedObjectContext != nil) {
        if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
            DDLogError(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        }
    }
}  

// main
- (NSManagedObjectContext *)managedObjectContext {
    if (_managedObjectContext != nil) {
        return _managedObjectContext;
    }

    _managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    _managedObjectContext.parentContext = [self saveManagedObjectContext];

    return _managedObjectContext;
}

// save context, parent of main context
- (NSManagedObjectContext *)saveManagedObjectContext {
    if (_writerManagedObjectContext != nil) {
        return _writerManagedObjectContext;
    }

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil) {
        _writerManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
        [_writerManagedObjectContext setPersistentStoreCoordinator:coordinator];
    }
    return _writerManagedObjectContext;
}  

Und so sieht meine Importmethode jetzt aus:

- (void)import {
    NSManagedObjectContext *saveObjectContext = [AppDelegate saveManagedObjectContext];

    // create background context
    NSManagedObjectContext *bgContext = [[NSManagedObjectContext alloc]initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    bgContext.parentContext = saveObjectContext;

    [bgContext performBlock:^{
        NSArray *newCarsInfo = [self fetchNewCarInfoFromServer];

        // import the new data to Core Data...
        // I'm trying to do an efficient import here,
        // with few fetches as I can, and in batches
        for (... num of batches ...) {

            // do batch import...

            // save bg context in the end of each batch
            [bgContext save:&error];
        }

        // no call here for main save...
        // instead use NSManagedObjectContextDidSaveNotification to merge changes
    }];
}  

Und ich habe auch folgenden Beobachter:

[[NSNotificationCenter defaultCenter] addObserverForName:NSManagedObjectContextDidSaveNotification object:nil queue:nil usingBlock:^(NSNotification* note) {

    NSManagedObjectContext *mainContext = self.managedObjectContext;
    NSManagedObjectContext *otherMoc = note.object;

    if (otherMoc.persistentStoreCoordinator == mainContext.persistentStoreCoordinator) {
        if (otherMoc != mainContext) {
            [mainContext performBlock:^(){
                [mainContext mergeChangesFromContextDidSaveNotification:note];
            }];
        }
    }
}];

Antworten auf die Frage(3)

Ihre Antwort auf die Frage