我的数据库中有三个Applications
。我有一个删除一个谓词。
给出以下代码:
[Application MR_deleteAllMatchingPredicate: applicationDeletePredicate];
[[NSManagedObjectContext MR_defaultContext] MR_saveToPersistentStoreAndWait];
NSLog(@"We have %ld apps left.", [Application MR_countOfEntities]);
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"We have %ld apps left.", [Application MR_countOfEntities]);
});
我收到以下日志消息:
We have 2 apps left.
We have 3 apps left.
所以它已经正确删除了谓词,但是当我尝试在主队列中重新加载时,应用程序仍然存在。我做错了吗?在处理MagicalRecord
时(在我的计数方法中)我是否应该始终指定默认上下文?
答案 0 :(得分:11)
尽管MagicalRecord确实提供了减少打字的方法,但您需要了解幕后发生的事情,以避免出现类似情况。
特别是,您需要了解MagicalRecord何时创建新的上下文以及如何配置它们。
MagicalRecord为需要上下文的操作提供方法,但这些方法不将上下文作为参数。在这些情况下,MagicalRecord使用[NSManagedObjectContext MR_contextForCurrentThread]
方法来获取默认上下文或创建一个新的上下文,该上下文是默认上下文的子项。如果它创建了一个新的上下文,它会为当前线程缓存它以供以后重用(考虑到Apple使用队列并发类型的上下文的方向,当你使用块内的对象时,这是一个不好的做法。)
但长话短说,这里可能会发生什么。
[Application MR_deleteAllMatchingPredicate: applicationDeletePredicate];
创建一个新的上下文,它是默认上下文的子项,并执行删除。[[NSManagedObjectContext MR_defaultContext] MR_saveToPersistentStoreAndWait];
(从主线程非法调用,考虑到1.顺便说一下)保存了不知道删除的默认上下文,因为从未保存子上下文并且没有推送更改到父,默认,上下文。[Application MR_countOfEntities]
在与删除相同的上下文中运行并返回新计数。[Application MR_countOfEntities]
在主队列上运行。因为它在主线程上运行,所以它使用默认上下文,从未看到过这个删除,因为child从未保存过。所以它返回旧计数。您需要做的是确保保存子上下文及其所有父项。因此,您可能需要将第二行中的默认上下文替换为当前线程的上下文:[[NSManagedObjectContext MR_contextForCurrentThread] MR_saveToPersistentStoreAndWait];
。
但我会避免隐藏的上下文创建,并会明确地创建它们。所以我的第一个建议是避免使用不将上下文作为参数的MagicalRecord方法(当有相似的方法时)。
我的第二个建议是不使用MagicalRecord,而是直接使用Core Data。首先,您可以使用全局使用的两个上下文:一个具有主队列并发类型的上下文,您将在主线程上使用它来更新UI。另一个具有私有队列并发类型的用户,可用于所有后台任务,并配置为主要上下文的子级。