tim*_*tim 5 core-data objective-c ios magicalrecord
我在NSManagedObjectContext上的GCD调度队列中进行操作,如下所示:
- (NSManagedObjectContext *)backgroundContext
{
if (backgroundContext == nil) {
self.backgroundContext = [NSManagedObjectContext MR_contextThatNotifiesDefaultContextOnMainThread];
}
return backgroundContext;
}
Run Code Online (Sandbox Code Playgroud)
MR_contextThatNotifiesDefaultContextOnMainThread是MagicalRecord的方法:
NSManagedObjectContext *context = [[self alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[context setParentContext:[NSManagedObjectContext MR_defaultContext]];
return context;
Run Code Online (Sandbox Code Playgroud)
获取对象并为其提供正确的队列位置后,我记录它们并且顺序正确.但是,第二个日志似乎是完全随机的,排序描述符显然不起作用.
我把问题缩小到了[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);
}
});
Run Code Online (Sandbox Code Playgroud)
我不知道为什么排序描述符不起作用,任何核心数据专家都想帮忙吗?
更新:
在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);
}
}];
}
}
Run Code Online (Sandbox Code Playgroud)
更新3:
MagicalRecord提供了一种递归保存上下文的方法,现在我的代码如下所示:
if ([[NSManagedObjectContext MR_contextForCurrentThread] hasChanges]) {
DLog(@"Changes");
[[NSManagedObjectContext MR_contextForCurrentThread] MR_saveWithErrorHandler:^(NSError *error) {
DLog(@"Error saving context: %@", error);
}];
}
Run Code Online (Sandbox Code Playgroud)
首先不使用它让我感到羞耻...
但是,我不知道为什么这会有所帮助,并希望得到解释.
我会尝试发表评论,因为我写了 MagicalRecord。
因此,在iOS5上,MagicalRecord被设置为尝试使用多个托管对象上下文的新Private Queue方法。这意味着子上下文中的保存只会将保存推送到父上下文。仅当没有更多父级的父级保存时,保存才会持久保存到其存储中。这可能是您的 MagicalRecord 版本中发生的情况。
MagicalRecord 已在后续版本中尝试为您处理此问题。也就是说,它会尝试在私有队列模式和线程隔离模式之间进行选择。正如您所发现的,这效果不太好。为 iOS4 和 iOS5 编写代码(无需复杂的预处理器规则等)的唯一真正兼容的方法是使用经典的线程隔离模式。1.8.3 标签中的 MagicalRecord 支持这一点,并且应该适用于两者。从 2.0 开始,将只有私有队列。
而且,如果您查看 MR_save 方法,您会发现它还为您执行 hasChanges 检查(这也可能是不需要的,因为 Core Data 内部也可以处理该检查)。无论如何,您需要编写和维护的代码更少......
| 归档时间: |
|
| 查看次数: |
1681 次 |
| 最近记录: |