2017-04-11 1 views
0

Parent_ContextCoredata - Multithreading bester Weg

Child_context (Set Parent_Context als Elternteil)

Child_context im Hintergrund zu verwenden, um neue Daten hinzuzufügen oder bestehende zu aktualisieren. Parent_Context zur Anzeige auf der Benutzeroberfläche und zum Speichern des persistenten Datenspeichers.

Child_context speichern sollte nicht dauern, da Änderungen nur im Speicher aktualisiert werden. Das wird auf Parent_Context aktualisiert.

Das Speichern von Parent_Context kann beim Schreiben in den Speicher etwas dauern. So können wir wählen, wann Parent_Context basierend auf der Notwendigkeit der Anwendung gespeichert wird.

So verwende ich normalerweise Kontext, wenn in Multithread-Umgebung benötigt oder um UI zu aktualisieren, während weiterhin auf Daten im Hintergrund zugegriffen wird.

// Parent or main 
_mainQueueContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; 
_mainQueueContext.persistentStoreCoordinator = self.persistentStoreCoordinator; 

// Child or background context 
_privateQueueContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; 
[_privateQueueContext setParentContext:self.mainQueueContext]; // Set main threads MOC as parent. 

//To Save 
    if ([self privateQueueContext].hasChanges) { 
     [[self privateQueueContext] performBlockAndWait:^{ 
      NSError *childError = nil; 
      if ([[self privateQueueContext] save:&childError]) { 
       [[self mainQueueContext] performBlock:^{ 
        NSError *parentError = nil; 
        if (![[self mainQueueContext] save:&parentError]) { 
         DLog(@"Error saving parent, error: %@", [parentError localizedDescription]); 
        } 
       }];   
      } else { 
       DLog(@"Error saving child, error: %@", [childError localizedDescription]); 
      } 
     }]; 
    } 

Wenn es eine bessere Art und Weise ist eine solche Situation zu handhaben, bitte teilen. Vielen Dank.

Durch Speichern des Kontexts im Hintergrund Thread sehe ich nicht UI einfrieren. Stellen Sie Fragen, um andere bessere Wege zu kennen und mehr über Kerndaten zu erfahren.

Antwort

2

Ich bevorzuge mindestens 2 Kontexte.

Der Hauptspeicher, der dem persistenten Speicher zugeordnet ist (ohne übergeordnete Kontexte), lautet privateQueueConcurrencyType, sodass die Benutzeroberfläche während der Speichervorgänge nicht betroffen ist.

Der zweite ist ViewContext for UI, der der untergeordnete Kontext für den privateContext ist.

Ich habe normalerweise eine andere für Hintergrund-Import, die ein Kind Kontext des UI-Kontext ist und als privateQueueConcurrencyType konfiguriert ist, so dass es nicht die Benutzeroberfläche blockiert. Beim Speichern wird die Benutzeroberfläche aktualisiert, und dann werden Änderungen im permanenten Speicher gespeichert (wenn sie rekursiv gespeichert werden).

Ich erstelle auch Einweg-Kind-Kontexte zu dem ViewContext, wann immer ich Änderungen vornehmen werde. Ich mache die Änderungen im childContext und speichere rekursiv. Ich finde so meinen Hintern mehrere Male in Multi-User-Situationen gespeichert.

Unten ist mein Setup:

lazy var privateSaveContext: NSManagedObjectContext = { 
    let moc = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType) 
    moc.name = "privateSaveContext" 
    moc.persistentStoreCoordinator = self.coordinator 
    moc.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy 
    return moc 
}() 

lazy var viewContext: NSManagedObjectContext = { 
    let moc = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType) 
    moc.name = "viewContext" 
    moc.parent = self.privateSaveContext 
    moc.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy 
    return moc 
}() 

lazy var importContext: NSManagedObjectContext = { 
    let moc = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType) 
    moc.name = "importContext" 
    moc.parent = self.viewContext 
    moc.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy 
    return moc 
}() 

Wenn auf der Festplatte zu speichern, ich spare rekursiv:

class func save(_ moc: NSManagedObjectContext) { 
    moc.performAndWait { 
     if moc.hasChanges { 
      DLog("Inserted objects count = \(moc.insertedObjects.count)") 
      do { 
       try moc.save() 
       if moc.parent == nil { DLog("SAVED changes to persistent store") } 
       DLog("SAVED context '\(moc)'") 
      } catch { 
       DLog("ERROR saving context '\(moc)' - \(error)") 
      } 
     } else { 
      if moc.parent == nil { DLog("SKIPPED saving changes to persistent store, because there are no changes") } 
      DLog("SKIPPED saving context '\(moc)' because there are no changes") 
     } 
     if let parentContext = moc.parent { 
      save(parentContext) 
     } 
    } 
} 

P. S. DLog ist etwas, das ich verwende, so dass es den Funktionsnamen, das Datum, die Uhrzeit usw. ausdruckt. Sie können das einfach zu print ändern.

+0

Danke für den Austausch von Details. Ich mag die Art, wie Sie es tun, wenn ich neue Daten während der Anzeige abrufen muss. In meinem Fall habe ich privaten und Hauptkontext, um im Hintergrund abzurufen und UI beziehungsweise zu aktualisieren. Nochmals vielen Dank für Ihre Antwort. (Aber um die Rechte zu bekommen, um zu wählen :)) – Sharan

+0

Sie können immer die Antwort akzeptieren, wenn Sie damit zufrieden sind. – oyalhi

+0

** Sicher! ** @oyalhi – Sharan

Verwandte Themen