我正在使用类似以下方式定义的NSManagedObjectContext在GCD调度队列中进行操作:
- (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);
}];
}
我真该早点使用它...
但是,我不知道为什么它会有帮助,我很想得到一个解释。