【发布时间】:2012-04-12 09:30:15
【问题描述】:
我正在 GCD 调度队列中对 NSManagedObjectContext 进行操作,定义如下:
- (NSManagedObjectContext *)backgroundContext
{
if (backgroundContext == nil) {
self.backgroundContext = [NSManagedObjectContext MR_contextThatNotifiesDefaultContextOnMainThread];
}
return backgroundContext;
}
MR_contextThatNotifiesDefaultContextOnMainThread 是来自MagicalRecord 的方法:
NSManagedObjectContext *context = [[self alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[context setParentContext:[NSManagedObjectContext MR_defaultContext]];
return context;
在获取我的对象并为它们提供正确的队列位置后,我记录它们并且顺序是正确的。但是,第二个日志似乎是完全随机的,排序描述符显然不起作用。
我已将问题范围缩小到[self.backgroundContext save:&error]。保存后后台上下文排序描述符坏了。
dispatch_group_async(backgroundGroup, backgroundQueue, ^{
// ...
for (FooObject *obj in fetchedObjects) {
// ...
obj.queuePosition = [NSNumber numberWithInteger:newQueuePosition++];
}
NSFetchRequest *f = [NSFetchRequest fetchRequestWithEntityName:[FooObject entityName]];
f.predicate = [NSPredicate predicateWithFormat:@"queuePosition > 0"];
f.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"queuePosition" ascending:YES]];
NSArray *queuedObjects = [self.backgroundContext executeFetchRequest:f error:nil];
for (FooObject *obj in queuedObjects) {
DLog(@"%@ %@", obj.queuePosition, obj.title);
}
if ([self.backgroundContext hasChanges]) {
DLog(@"Changes");
NSError *error = nil;
if ([self.backgroundContext save:&error] == NO) {
DLog(@"Error: %@", error);
}
}
queuedObjects = [self.backgroundContext executeFetchRequest:f error:nil];
for (FooObject *obj in queuedObjects) {
DLog(@"%@ %@", obj.queuePosition, obj.title);
}
});
我不知道为什么排序描述符不起作用,有任何 Core Data 专家想帮忙吗?
更新:
iOS 4 上不会出现这个问题。我认为原因是线程隔离和私有队列模式之间的差异。 MagicalRecord 自动使用新的并发模式,它的行为似乎有所不同。
更新 2:
通过添加背景上下文的保存解决了问题:
if ([[NSManagedObjectContext MR_contextForCurrentThread] hasChanges]) {
DLog(@"Changes");
NSError *error = nil;
if ([[NSManagedObjectContext MR_contextForCurrentThread] save:&error] == NO) {
DLog(@"Error: %@", error);
} else {
NSManagedObjectContext *parent = [NSManagedObjectContext MR_contextForCurrentThread].parentContext;
[parent performBlockAndWait:^{
NSError *error = nil;
if ([parent save:&error] == NO) {
DLog(@"Error saving parent context: %@", error);
}
}];
}
}
更新 3:
MagicalRecord 提供了一种递归保存上下文的方法,现在我的代码如下所示:
if ([[NSManagedObjectContext MR_contextForCurrentThread] hasChanges]) {
DLog(@"Changes");
[[NSManagedObjectContext MR_contextForCurrentThread] MR_saveWithErrorHandler:^(NSError *error) {
DLog(@"Error saving context: %@", error);
}];
}
因为我一开始没有使用它而感到羞耻......
但是,我不知道为什么这会有所帮助,并希望得到解释。
【问题讨论】:
标签: objective-c ios core-data magicalrecord