核心数据拉动变化
Posted
技术标签:
【中文标题】核心数据拉动变化【英文标题】:Core Data pulling changes 【发布时间】:2014-07-10 12:52:18 【问题描述】:好的,问题来了:我使用managedObjectContext
层次结构。我有一个根 managedObjectContext
是单例的,所以我可以共享相同的上下文,同时我可以有子上下文来分离保存。
_managedObjectContext = [[NSManagedObjectContext alloc]initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
_managedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
这就是我创建子managedObjectContext
的方式,每个viewController
都有一个
NSManagedObjectContext* childContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
childContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
childContext.parentContext = _managedObjectContext;
对于那些认为只保存孩子managedObjectContext
就足够的人来说,保存只对一个祖先起作用,你必须这样做直到父母是nil
。我只有父母和孩子,所以这是我保存数据以存储的代码
- (void)saveChildContext:(NSManagedObjectContext*)childContext
[childContext performBlockAndWait:^
NSError* error;
[childContext save:&error];
[_managedObjectContext performBlock:^
NSError* parentError;
[_managedObjectContext save:&parentError];
];
];
我有一个viewController
,它为tableView
获取数据。
arrObjects = [dbClient getEntitiesOfType:@"Object" predicate:@"%K == nil || %K.length < 1" predicateArray:[NSArray arrayWithObjects:@"someRelationship.property", @"someRelationship.otherProperty", nil] childContext:childContext];
这是在后面:
- (NSArray*)getEntitiesOfType:(NSString *)entityType predicate:(NSString*)predicateString predicateArray:(NSArray*)predicateArray childContext(NSManagedObjectContext*)context
NSManagedObjectContext* managedObjectContext;
if (context != nil)
managedObjectContext = context;
else
managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil)
NSEntityDescription* entityDescription = [NSEntityDescription entityForName:entityType inManagedObjectContext:managedObjectContext];
NSPredicate* predicate = [NSPredicate predicateWithFormat:predicateString argumentArray:predicateArray];
NSFetchRequest* request = [[NSFetchRequest alloc] init];
request.entity = entityDescription;
request.predicate = predicate;
NSError* error = [[NSError alloc] init];
return [managedObjectContext executeFetchRequest:request error:&error];
else
return nil;
当查看获取结果之一的详细信息时,我会进行更改,保存上下文,将更改传播到父级然后存储。我传递了对象,并详细说明了我使用对象的managedObjectContext
。将数据保存到存储后,我弹出我的viewController
,一切都很好。
如果我选择在另一个 viewController
上对该对象执行某些操作,我会保存上下文,因为我进行了一些更改,传递 objectId
,我使用另一个 managedObjectContext
获取该对象,但它具有相同的父对象,进行更改并将其保存到父级,然后存储。一切都保存得很好。哦,这里我用NSNotification
,因为viewControllers
不知道对方的存在。
[self.navigationController popViewControllerAnimated:NO];
NSDictionary* userInfo = [NSDictionary dictionaryWithObjectsAndKeys:currentTrip.objectID, @"ObjectId", nil];
[[NSNotificationCenter defaultCenter] postNotificationName:@"tripRecording" object:nil userInfo:userInfo];
问题是当我到达第一个viewController
(tableViewController
) 时,我在viewWillAppear
上获取数据,但我没有得到任何更改。另一方面,如果我在同一视图上按下段,获取另一个数据,然后返回第一个段,按下它并再次获取第一组数据,我会得到正确的答案。这意味着无论我使用哪种上下文,数据都得到了正确存储。
我的问题是:
除非我更改 fetchRequest
然后再次获取第一个请求,否则managedObjectContext
怎么可能看不到更改?
reset
上的 managedObjectContext
是获取正确数据的唯一方法吗?
谢谢。
【问题讨论】:
1.向我们展示您的代码。 2. 请记住格式化您的问题,使它们看起来更好、更易读。 @Neeku 感谢您的评论 您应该使用NSPrivateQueueConcurrencyType
而不是NSMainQueueConcurrencyType
创建您的子上下文。这是我看到的第一件事。这是一个相当密集的问题,所以我想在提供完整答案之前多看看。
@random 但我想成为主线程...
@StanleyKubrick 只是因为它是 NSPrivateQueueConcurrencyType
并不意味着它不在主线程上。你应该只有一个NSMainQueueConcurrencyType
,这是你的master上下文。您创建 NSPrivateQueueConcurrencyType
的子上下文,该上下文引用回您的单个 NSMainQueueConcurrencyType
【参考方案1】:
这是我使用两个不同的NSManagedObjectContext
的设置:
创建我的主人NSManagedObjectContext
,我从不直接处理这个上下文:
- (NSManagedObjectContext *)masterManagedObjectContext
if (_masterManagedObjectContext != nil)
return _masterManagedObjectContext;
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil)
_masterManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_masterManagedObjectContext performBlockAndWait:^
[_masterManagedObjectContext setPersistentStoreCoordinator:coordinator];
];
return _masterManagedObjectContext;
即时创建一个新的NSManagedObjectContext
:
- (NSManagedObjectContext *)newManagedObjectContext
NSManagedObjectContext *newContext = nil;
NSManagedObjectContext *masterContext = [self masterManagedObjectContext];
if (masterContext != nil)
newContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[newContext performBlockAndWait:^
[newContext setParentContext:masterContext];
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter addObserver:self
selector:@selector(backgroundDidSaveNotification:)
name:NSManagedObjectContextDidSaveNotification
object:newContext];
];
return newContext;
新的NSManagedObjectContext
保存时监听的方法,以便它可以合并到master:
- (void)backgroundDidSaveNotification:(NSNotification*)notificaton
[self.masterManagedObjectContext mergeChangesFromContextDidSaveNotification:notificaton];
[self saveMasterContext];
为了清楚起见我的saveMasterContext
:
- (void)saveMasterContext
[self.masterManagedObjectContext performBlockAndWait:^
NSError *error = nil;
BOOL saved = [self.masterManagedObjectContext save:&error];
if (!saved)
// do some real error handling
NSLog(@"Could not save master context due to %@", error);
];
【讨论】:
谢谢。我会尝试mergeChangesFromContextDidSaveNotification
。但是如果孩子们将更改保存到父母,这还不足以让他们看到其他更改吗?虽然我使用相同的父上下文,但似乎我有两个。
子上下文不会自动从父上下文获取推送的更改。因此,如果一个孩子保存并推送给父母,除非您明确通知其他孩子,否则其他孩子不会知道。
对不起,我用错了词。当然,兄弟姐妹必须从父母那里提取数据,但我看不到它,除非我重置上下文。此外,我在获取其他东西时看到了变化,然后是我首先想要的东西。如果我只是获取我想要的东西,我看不到任何变化。
好的,我接受了你的回答。您和我的解决方案都很好。问题是,文章说得很好,如果您希望在同级上下文中看到合并的更改,您必须重置(我的解决方案)managedObjectContext
或创建新的。再次感谢,随机。以上是关于核心数据拉动变化的主要内容,如果未能解决你的问题,请参考以下文章