应用程序突然从“您非法改变 NSFetchedResultsController 的获取请求”的每次启动时崩溃,但解决方案令人不安

Posted

技术标签:

【中文标题】应用程序突然从“您非法改变 NSFetchedResultsController 的获取请求”的每次启动时崩溃,但解决方案令人不安【英文标题】:App suddenly crashes every launch from a "You have illegally mutated the NSFetchedResultsController's fetch request" but solution is unnerving 【发布时间】:2013-11-04 01:19:05 【问题描述】:

每次运行我的应用程序时,我都会突然收到以下错误:

CoreData:致命错误:部分信息的持久缓存与当前配置不匹配。你非法修改了 NSFetchedResultsController 的获取请求、谓词或排序描述符,而没有禁用缓存或使用 +deleteCacheWithName:

这是调用堆栈中的前十项:

*** First throw call stack:
(
    0   CoreFoundation                      0x04b835e4 __exceptionPreprocess + 180
    1   libobjc.A.dylib                     0x022c68b6 objc_exception_throw + 44
    2   CoreData                            0x020a1b41 -[NSFetchedResultsController performFetch:] + 913
    3   Syllable                            0x00036aa9 -[RootViewController fetchedResultsController] + 777
    4   Syllable                            0x0003772b -[RootViewController tableView:numberOfRowsInSection:] + 91
    5   UIKit                               0x00d1d240 -[UISectionRowData refreshWithSection:tableView:tableViewRowData:] + 2510
    6   UIKit                               0x00d20b3d -[UITableViewRowData numberOfRows] + 98
    7   UIKit                               0x00ba94c2 -[UITableView noteNumberOfRowsChanged] + 120
    8   UIKit                               0x00ba8e6f -[UITableView reloadData] + 814
    9   UIKit                               0x10378ed1 -[UITableViewAccessibility(Accessibility) reloadData] + 50
    10  UIKit                               0x00bac8d3 -[UITableView _reloadDataIfNeeded] + 65

它提供了更多信息,但似乎都源于我发布的第一个错误。如果它们有帮助,请告诉我,我会发布它们。

不过,这个问题真的很奇怪。它似乎是凭空出现的。即使我使用 git 恢复到以前的工作版本,它仍然会崩溃,所以我不知道是什么原因造成的。

有一个solution posted on ***,但这有点令人不安。将缓存设置为零会从我的应用程序中删除缓存能力/使其变慢吗?会带来什么后果?

我正在对我的应用进行新的更新,首要任务是确保我的现有/未来用户不会崩溃。


编辑:我相信这是导致问题的原因(尽管我已经删除它并且问题仍然存在):

我的 AppDelegate 中的 applicationDidFinishLaunching 中有以下代码,它主要用于在应用程序首次启动时在 Core Data 中创建一个特殊对象。在添加此问题后,问题似乎发生了,尽管此后不久删除了代码。我现在不应该操纵 Core Data(是不是太早了)?

// If it's the first time launching, create and add a sample article for an introduction
if ([[[NSUserDefaults standardUserDefaults] objectForKey:@"IsFirstTimeLaunching"] isEqualToString:@"YES"]) 
    NSManagedObjectContext *context = self.managedObjectContext;

    Article *article = [NSEntityDescription insertNewObjectForEntityForName:@"Article" inManagedObjectContext:context];
    article.source = @"text";
    article.body = @"some text";
    article.timeStamp = [NSDate date];

    NSError *error;
    [context save:&error];

    [[NSUserDefaults standardUserDefaults] setObject:@"NO" forKey:@"IsFirstTimeLaunching"];

我的 AppDelegate 中也有这个块,它已经存在了很长一段时间,但老实说,我不确定它到底是做什么的,我可能只是写了它而忘记完成它......

- (void)applicationDidEnterBackground:(UIApplication *)application

    NSManagedObjectContext *context = self.managedObjectContext;
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Article" inManagedObjectContext:context];
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    [request setEntity:entity];    

【问题讨论】:

不要更改获取请求。如果您要大量更改/更改 fetch 请求,则无论如何您都不想使用缓存。如果您介于两者之间,请使用缓存,但如果您更改获取请求参数,请先将其删除。 您之前更改过 Core Data 中的某些实体,出现了这个问题? 我添加了我认为可能触发了原始帖子中的错误的内容。你所说的大量改变 fetch 请求是什么意思?据我所知,我所做的唯一获取是通过 NSFetchedResultsController 并且它们是非常基本的检索调用 (objectAtIndexPath:),我不相信我会在此过程中改变任何东西。 【参考方案1】:

您有以下选择:

    将缓存设置为nil。如果您没有遇到性能问题,这实际上是可以的。如果提取需要很长时间,FRC 缓存确实对速度有很大帮助。首先尝试这个解决方案。

    设计一个具有不同缓存名称的方案。您的 FRC 可以确定在延迟实例化期间它必须执行哪个提取并使用适当的缓存名称。例如,如果您有一个搜索控制器,则可以使用范围按钮的状态。 对于此解决方案(并且如果您只使用一个缓存名称),如果您更改了 FRC 的 fetchRequest,请务必在获取的结果控制器上调用 performFetch。这正是导致这次崩溃的原因。相反,您可以将 FRC 设置为 nil 并让它自己懒惰地创建。

    在适当的时候用deleteCacheWithName:删除缓存。

【讨论】:

我用更多信息更新了原始帖子,是否有助于澄清? 抱歉,没有什么帮助。相反,您应该展示您的 FRC 实现。你试过nil 缓存吗? nil cacheName 确实修复了它,但我仍然对这可能对我的应用造成的影响感到不安。 您不必担心。如果第一次获取不是太慢,那么你就准备好了。

以上是关于应用程序突然从“您非法改变 NSFetchedResultsController 的获取请求”的每次启动时崩溃,但解决方案令人不安的主要内容,如果未能解决你的问题,请参考以下文章

当程序员突然从世界上消失

单个设备突然停止从我的服务器接收 C2DM 推送

WCF 突然停止工作

Meteor 应用突然不再在 iOS 上运行

C程序的执行速度突然提高

Visual C++ 函数突然变慢 170 毫秒(长 4 倍)