有了核心數據,看起來最好的學習方法就是與已有的工作進行比較。我會發布一些代碼來處理類似於你的情況。
第一:這是爲我的情況設置兩個上下文的正確方法嗎?
這是我在我的AppDelegate現在:
- (NSManagedObjectContext *)auxiliaryManagedObjectContext {
NSManagedObjectContext *managedObjectContext = nil;
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
managedObjectContext = [[NSManagedObjectContext alloc] init];
[managedObjectContext setPersistentStoreCoordinator:coordinator];
[managedObjectContext setUndoManager:nil];
}
return managedObjectContext;
}
- (NSManagedObjectContext *)managedObjectContext
{
if (_managedObjectContext != nil) {
return _managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
_managedObjectContext = [[NSManagedObjectContext alloc] init];
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
}
return _managedObjectContext;
}
二:這將是調用單獨的同步和 load方法的正確方法?
這真的取決於這些方法中發生了什麼。當您在後臺使用上下文時,應該發送設置通知,以便在發生更改時觸發。在這種方法中,你再合併從背景方面的變化到UI方面:
dispatch_queue_t background = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, (unsigned long) NULL);
dispatch_async(background, ^{
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSManagedObjectContext *backgroundManagedObjectContext = [appDelegate auxiliaryManagedObjectContext];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(mergeContexts:)
name:NSManagedObjectContextDidSaveNotification
object:backgroundManagedObjectContext];
NSManagedObject *threadSafeManagedObject =
[backgroundManagedObjectContext objectWithID:self.currentManagedObject.objectID];
NSManagedObject *insertedThreadSafeManagedObject = [NSEntityDescription insertNewObjectForEntityForName:@"Entity" inManagedObjectContext:backgroundManagedObjectContext];
NSError *error;
// Will call the mergeContexts: selector registered above
if(![backgroundManagedObjectContext save:&error]) {
NSLog(@"Error! %@", error);
}
});
- (void)mergeContexts:(NSNotification *)notification {
SEL selector = @selector(mergeChangesFromContextDidSaveNotification:);
[self.managedObjectContext performSelectorOnMainThread:selector withObject:notification waitUntilDone:YES];
}
在mergeContexts:方法,背景上下文合併的UI環境。從背景開始的背景停留在背景中是非常重要的,反之亦然。此外,託管對象不是線程安全的,因此要在後臺線程中使用UI線程中的一個,必須將其轉移到後臺上下文中查看objectID,如上例所示。
第三:我的核心數據集中在一個實體(用戶)周圍,其他實體都連接到其他實體。我是否必須創建一個局部變量 並在每次使用時都獲取它,或者是否有更好的方法,以便在兩個線程之間不共享NSManagedObject?
上面的描述應該回答了這個問題。
第四:如果我救母的背景下,將孩子 上下文(UI)自動更新,或者是有我 需要調用特定的方法?
這將是上述示例中的mergeContexts:方法。讓我知道這是否合理。
編輯1:initWithConcurrencyType
正如你提到的,還有NSMainQueueConcurrencyType和NSPrivateQueueConcurrencyType是處理這一回之間的背景和UI背景下提出交換站管理對象上下文的初始化期間使用。
AppDelegate初始值設定項實際上是相同的。唯一的區別是初始化語句:
// Background context
managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
// Main thread context
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
你可以這樣從你搶的背景情況下,在這種情況下的AppDelegate和使用後臺線程開展工作,完成主線程的工作:
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSManagedObjectContext *backgroundManagedObjectContext = [appDelegate auxiliaryManagedObjectContext];
[backgroundManagedObjectContext performBlock:^{
// Do work
[self.managedObjectContext performBlock:^{
// merge work into main context
}];
}];
重要的是聲明適用相同的線程安全規則(例如,必須將背景對象傳送到主線程視圖的objectID)。要將工作從後臺線程傳遞到主線程,應該在後臺上下文的執行塊中調用主線程上下文的performBlock。儘管合併上下文的便利性仍在於通知安排內容,無論您如何初始化上下文。
編輯2:父/子上下文
這裏是Correct implementation of parent/child NSManagedObjectContext父/子例如:
- (void)saveContexts {
[childContext performBlock:^{
NSError *childError = nil;
if ([childContext save:&childError) {
[parentContext performBlock:^{
NSError *parentError = nil;
if (![parentContext save:&parentError]) {
NSLog(@"Error saving parent");
}
}];
} else {
NSLog(@"Error saving child");
}
}];
}
在我們的例子中,初始化子上下文時,其父設置爲你的UI上下文:
[backgroundManagedObjectContext setParentContext:_managedObjectContext];
當'mainManagedObjectContext'被調用時'_backgroundManagedObjectContext'是否可能是'nil'? –
@AaronBrager這就是我問這是否是正確設置的原因。我應該檢查' - (NSManagedObjectContext *)mainManagedObjectContext'方法嗎? – carloabelli
或者你可以使用'[self backgroundManagedObjectContext]'而不是'_ _backgroundManagedObjectContext',如果它沒有實例化,它會實例化它。 –