我有一個雙重託管對象上下文設置,我有一個父/子MOC關係。父級負責直接寫入專用隊列中的數據庫(NSPrivateQueueConcurrencyType),然後我有一個負責爲主線程(NSMainQueueConcurrencyType)提取和保存數據的子上下文。託管對象上下文不合並來自後臺上下文的變更
上下文的工作方式與我在更改主隊列上下文並保存時一樣,然後將更改合併到後臺隊列上下文並在後臺線程上寫入數據庫。
我遇到的問題是當我直接將數據寫入背景隊列上下文,然後嘗試將它合併到主隊列上下文。這些對象在商店中正確存儲,並且當我合併這些更改時似乎可行。但是,如果我試圖在將數據保存到存儲後直接對主隊列上下文創建NSFetchRequest,那麼數據是陳舊的,而不是正確的更新數據。
下面是代碼摘錄,應該幫助您瞭解我在做什麼。有些需要注意的是從JSON工作中正確返回NSManagedObjects的邏輯。此外,我已經測試並且在UI嘗試對主隊列MOC發出任何提取請求之前運行mergeChangesFromContextDidSaveNotification。你們都有什麼想法發生了什麼?
// Context Setup
- (NSManagedObjectContext *)backgroundWriterManagedObjectContext
{
if (_backgroundWriterManagedObjectContext != nil)
return _backgroundWriterManagedObjectContext;
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil)
{
_backgroundWriterManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
_backgroundWriterManagedObjectContext.persistentStoreCoordinator = coordinator;
_backgroundWriterManagedObjectContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy;
_backgroundWriterManagedObjectContext.undoManager = nil;
}
return _backgroundWriterManagedObjectContext;
}
- (NSManagedObjectContext *)managedObjectContext
{
if (_managedObjectContext != nil)
return _managedObjectContext;
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil)
{
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
_managedObjectContext.parentContext = _backgroundWriterManagedObjectContext;
_managedObjectContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy;
_managedObjectContext.stalenessInterval = 0.0;
}
return _managedObjectContext;
}
// save MOC
- (void)saveManagedObjectContext
{
@try
{
// perform synchronous process to save to the main MOC
[_managedObjectContext performBlockAndWait:^(void)
{
__block NSError *error = nil;
// push any changes in the main context to the background writer context
if (![_managedObjectContext tryLock])
[VS_Log VS_LogError:[NSString stringWithFormat:@"VS_CoreDataManger - Unable To Lock Managed Object Context: %@", error.localizedDescription]];
if (![_managedObjectContext save:&error])
[VS_Log VS_LogError:[NSString stringWithFormat:@"VS_CoreDataManger - Error Saving Managed Object Context: %@", error.localizedDescription]];
[_managedObjectContext unlock];
// save the background writer context
[_backgroundWriterManagedObjectContext performBlock:^(void)
{
error = nil;
if (![_backgroundWriterManagedObjectContext tryLock])
[VS_Log VS_LogError:[NSString stringWithFormat:@"VS_CoreDataManger - Unable To Lock Background Writer Managed Object Context: %@", error.localizedDescription]];
if (![_backgroundWriterManagedObjectContext save:&error])
[VS_Log VS_LogError:[NSString stringWithFormat:@"VS_CoreDataManger - Error Saving Background Writer Managed Object Context: %@", error.localizedDescription]];
[_backgroundWriterManagedObjectContext unlock];
}];
}];
}
@catch (NSException *exception)
{
[VS_Log VS_LogException:exception];
}
}
// This code runs when attempting to save objects from a web service call
[_backgroundWriterManagedObjectContext performBlock:^(void)
{
// create a new process object and add it to the dictionary
__block VS_CoreDataRequest *request = [[VS_CoreDataRequest alloc] init];
// .. LOGIC HERE DESERIALIZES THE JSON AND RETURNS AN ARRAY OF NSMANAGEDOBJECTS
// perform synchronous process to save to the main MOC
@try
{
NSError *error = nil;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mergeChangesFromContextDidSaveNotification:) name:NSManagedObjectContextDidSaveNotification object:_backgroundWriterManagedObjectContext];
if (![_backgroundWriterManagedObjectContext tryLock])
[VS_Log VS_LogError:[NSString stringWithFormat:@"VS_CoreDataManger - Unable To Lock Background Writer Managed Object Context: %@", error.localizedDescription]];
if (![_backgroundWriterManagedObjectContext save:&error])
[VS_Log VS_LogError:[NSString stringWithFormat:@"VS_CoreDataManger - Error Saving Background Writer Managed Object Context: %@", error.localizedDescription]];
[_backgroundWriterManagedObjectContext unlock];
// submit changes back to the forground context
[_managedObjectContext performBlock:^(void)
{
NSMutableArray *objects = [[NSMutableArray alloc] init];
// iterate through the updated objects and find them in the main thread MOC
for (VS_BaseManagedObject *object in request.objects)
{
// get the object from the main managed object context
NSError *error;
NSManagedObject *obj = [_managedObjectContext existingObjectWithID:object.objectID error:&error];
if (error)
[VS_Log VS_LogError:[NSString stringWithFormat:@"VS_CoreDataManager - Error: %@", error.localizedDescription]];
if (obj)
{
[_managedObjectContext refreshObject:obj mergeChanges:YES];
[objects addObject:obj];
}
}
// RETURN FROM METHOD SO UI CAN REGAIN CONTROL
}];
}
@catch (NSException *exception)
{
[VS_Log VS_LogException:exception];
return;
}
}];
// Merges changes from parent to child context
- (void)mergeChangesFromContextDidSaveNotification:(NSNotification *)notification
{
// remove observer
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSManagedObjectContextDidSaveNotification object:_backgroundWriterManagedObjectContext];
// merge the changes
[_managedObjectContext mergeChangesFromContextDidSaveNotification:notification];
}
由於您的代碼和概念看起來不錯,所以您提供的信息中沒有任何意義。您是否使用FRC將數據提供給視圖?如果是這樣,我懷疑它與你的FRC有更多關係。我不確定獨立訪存是否會按照您的要求更新MOC。我會研究一下。 – andrewbuilder 2016-03-01 00:28:15