应用程序突然崩溃,因为"你已经非法改变了NSFetchedResultsController的获取请求",但解决方案令人不安

Dou*_*ith 6 core-data objective-c nsfetchedresultscontroller ios

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

CoreData:FATAL ERROR:节信息的持久缓存与当前配置不匹配.您已经非法改变了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
Run Code Online (Sandbox Code Playgroud)

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

但问题确实很奇怪.它似乎无处不在.即使我使用git恢复到以前工作的版本它仍然崩溃,所以我不知道是什么导致它.

在Stackoverflow上发布了一个解决方案,但它有点令人不安.将缓存设置为nil会从我的应用程序中移除缓存功能/使其变慢吗?会带来什么样的影响?

我正在为我的应用程序进行新的更新,优先考虑的是确保我的预先存在/未来用户不会崩溃.


编辑:我认为这是导致问题的原因(虽然我已经删除它并且问题仍然存在):

我的applicationDidFinishLaunchingAppDelegate中有以下代码,它主要用于在应用程序首次启动时在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"];
}
Run Code Online (Sandbox Code Playgroud)

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

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    NSManagedObjectContext *context = self.managedObjectContext;
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Article" inManagedObjectContext:context];
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    [request setEntity:entity];    
}
Run Code Online (Sandbox Code Playgroud)

Mun*_*ndi 1

您有以下选择:

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

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

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