47

我使用 NSFetchedResultsController 来显示一堆对象,这些对象是使用日期划分的。在全新安装时,一切正常,对象显示在表格视图中。但是,似乎当应用程序重新启动时我遇到了崩溃。我在初始化 NSFetchedResultsController 时指定了一个缓存,而当我不这样做时,它可以正常工作。

以下是我创建 NSFetchedResultsController 的方法:

- (NSFetchedResultsController *)results {
    // If we are not nil, stop here
    if (results != nil)
        return results;

    // Create the fetch request, entity and sort descriptors
    NSFetchRequest *fetch = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Event" inManagedObjectContext:self.managedObjectContext];
    NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:@"utc_start" ascending:YES];
    NSArray *descriptors = [[NSArray alloc] initWithObjects:descriptor, nil];

    // Set properties on the fetch
    [fetch setEntity:entity];
    [fetch setSortDescriptors:descriptors];

    // Create a fresh fetched results controller
    NSFetchedResultsController *fetched = [[NSFetchedResultsController alloc] initWithFetchRequest:fetch managedObjectContext:self.managedObjectContext sectionNameKeyPath:@"day" cacheName:@"Events"];
    fetched.delegate = self;
    self.results = fetched;

    // Release objects and return our controller
    [fetched release];
    [fetch release];
    [descriptor release];
    [descriptors release];
    return results;
}

这些是我在应用程序崩溃时收到的消息:

FATAL ERROR: The persistent cache of section information does not match the current configuration.  You have illegally mutated the NSFetchedResultsController's fetch request, its predicate, or its sort descriptor without either disabling caching or using +deleteCacheWithName:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'FATAL ERROR: The persistent cache of section information does not match the current configuration.  You have illegally mutated the NSFetchedResultsController's fetch request, its predicate, or its sort descriptor without either disabling caching or using +deleteCacheWithName:'

我真的不知道它为什么这么说,因为我不相信我正在做任何会导致这种情况的特殊行为。唯一的潜在问题是节标题(天),我在创建新对象时这样构造:

// Set the new format
[formatter setDateFormat:@"dd MMMM"];

// Set the day of the event
[event setValue:[formatter stringFromDate:[event valueForKey:@"utc_start"]] forKey:@"day"];

就像我提到的,如果不涉及缓存,所有这些都可以正常工作。任何帮助表示赞赏!

4

12 回答 12

65

当 Apple 发布新的 iOS 4.0 时,我的一个应用程序也遇到了类似的问题。搜索:

fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:[self managedObjectContext] sectionNameKeyPath:nil cacheName:nil];

并将参数cacheName的值设置为nil。它对我有用,希望对你有用。让我知道。

于 2010-07-29T13:49:05.843 回答
30

当我通过 MacBook Pro 升级到 Snow Leopard 10.6.4 和最新的 SDK 时,我开始遇到同样的错误。

事实证明,我们中的许多人一直在使用不符合规则的代码,但我们并不知道,因为 CoreData 并没有真正按照自己的规则行事。

具体来说,当您获取内容时,它们会被缓存,并且在 4.0 中,缓存不会在早期 SDK 中被清除的情况下自动清除。

对我来说,解决方案很简单。我刚刚使用了清除缓存的类方法。您可以指定一个单独的实体,但我指定了 nil,所以它只是在这段特定的启动代码中完成所有这些:

[NSFetchedResultsController deleteCacheWithName:nil];

突然间,我为熟悉 CoreData 而开发的小应用程序又开始工作了。

于 2010-08-01T20:44:44.620 回答
15

直接来自文档NSFetchedResultsController

修改获取请求

您不能简单地更改获取请求来修改结果。如果要更改获取请求,则必须:

  1. 如果您正在使用缓存,请将其删除(使用deleteCacheWithName:)。如果要更改获取请求,通常不应使用缓存。

  2. 更改获取请求。

  3. 调用performFetch:.

于 2012-01-01T03:26:03.750 回答
6

我遇到了类似的问题。当我检查调试器控制台时,它显示了缓存对象和获取的对象是什么,以便我可以找出它们不一致的原因。就我而言,这是由于不同的谓词造成的。

由于我的谓词中的值不是动态的,我可以为每个谓词指定不同的缓存名称。这将为我指定的每个“类型”创建一个缓存。

我想您将不得不评估您对缓存的需求。指定 nil 意味着每次调用都会进行一次提取。

我发现只有当获取请求有一些变化时才会发生错误。如果您正在创建一个新的 NSFetchRequest 或更改谓词 OR 排序描述符,那么您应该删除缓存或使用不同的缓存。否则,请确保您具有相同的 NSFetchRequest 或确保您的 NSFetchedResultsController 被保留,这应该可以解决您的问题。

于 2011-03-10T18:55:40.050 回答
3

如果您使用的是模拟器,请尝试重置它——我猜您已经更改了实体映射并且它被剩余的缓存弄糊涂了。如果没有,您可以尝试执行错误说明:

- (void)applicationWillTerminate:(UIApplication *)application {
    [NSFetchedResultsController deleteCacheNamed:@"Events"];
    //etc
}
于 2010-04-25T20:26:04.447 回答
3

Xcode 7(beta 4)仍然发生异常:

你在没有禁用缓存或使用 +deleteCacheWithName 的情况下非法改变了 NSFetchedResultsController 的获取请求、谓词或排序描述符:

注意:这是一个未经修改的 Xcode“模板”Master-Detail iOS 应用程序,带有使用 Xcode 7 创建的标准 Xcode CoreData “样板”代码并使用最新 (iOS 9) 部署目标。

当我在模拟器中重新启动我的应用程序时,我首先注意到了这一点。我已经通过 Xcode 多次启动和停止该应用程序,然后它发生了;它一直在发生。我决定做一些实验,结果:

  • 每次我在模拟器中停止应用程序时,我都会在后续启动时遇到异常。
  • 每次我使用模拟器的主页按钮停止应用程序时,我都能成功再次启动它。

仍然可以使用以下方法之一或其他方法解决此问题:

  • 在 AppDelegate 的application didFinishLaunchingWithOptions方法中,添加以下 SwiftNSFetchedResultsController.deleteCacheWithName(nil)或 Objective-C[NSFetchedResultsController deleteCacheWithName:nil];代码。这将清除损坏的缓存。
  • 在 Simulator 中,从Simulator菜单中,选择Reset Content and Settings。这解决了问题,但您丢失了测试数据

我也相信这是通过 Xcode 运行并在应用程序能够清理之前停止应用程序的产物。我在实际设备中没有看到这一点。

于 2015-08-07T02:44:25.237 回答
1

您是使用主页按钮退出模拟器还是通过在 Xcode 中终止应用程序?也许应用程序没有时间完成对缓存的写入。尝试使用主页按钮退出应用程序。

于 2010-04-25T23:06:12.440 回答
1

我遇到了同样的问题。
为了解决这个问题,我把[NSFetchedResultsController deleteCacheWithName:@"cacheName"];resultsController 的 init 放在了前面。为我工作,因为他只第一次去那里。

于 2012-01-07T16:35:43.637 回答
1

有多少类实现相同的 - (NSFetchedResultsController *)results 方法,你是否为每个类使用不同的缓存?我遇到了同样的问题,我想我可以通过在某些类别中使用不同的缓存名称来解决它,因为我有不同的 NSPredicates。

于 2010-06-25T21:47:20.463 回答
1

对于那些现在遇到同样问题的人来说,问题在于 Core Data 不会以某种方式清理缓存,所以第一次工作正常,但之后就不行了。然后将这一行放在初始化 NSFetchRequest 之后

[NSFetchedResultsController deleteCacheWithName:@"Name"];
于 2014-05-16T19:20:58.537 回答
1

我通过 Ray Wenderlich论坛发现

请注意,当您向数据存储区添加新内容时,即尚未加载 Locations 视图时,它只会在尚未创建获取请求时崩溃。如果视图已经加载,那么它工作正常。奇怪,嗯?

所以,在我的情况下发生的事情是这样的:

  1. 正常的启动过程需要构造一个 NSFetchedResultsController。
  2. 因为有数千个对象被提取,所以新的提取需要相当长的时间。为了缓解这种情况,获取 a) 使用缓存,b) 发生在后台,允许其他活动继续
  3. 通常,虽然 UI 是响应式的并且用户可以做一些事情,但在用户表达创建新对象的愿望之前很久就完成了获取。
  4. 但是,有时应用程序会在后台启动 - 例如,从 WatchKit 事件或后台获取等) - 启动的一部分将需要立即在数据存储中创建一个新对象。
  5. 如果在获取完成之前创建了新对象,则应用程序将崩溃。

解决方案是在创建对象之前确保fetch 完成(这会影响 fetch)。

或者,您可以删除缓存,但实际上性能较差。

请注意,来自调试器的警告是

你非法改变了 NSFetchedResultsController 的获取请求、谓词或排序描述符,而没有禁用缓存或使用 +deleteCacheWithName:

根本不会捕获这种情况,因为您更改的不是请求、谓词或排序描述符,而是更准确地说可以描述为在 fetch 正在进行时改变了结果集

我花了很长时间才找到这个小小的琐事。我希望你受益。

于 2015-07-29T17:17:48.433 回答
-2
NSFetchedResultsController *fetched = [[NSFetchedResultsController alloc] initWithFetchRequest:fetch managedObjectContext:self.managedObjectContext sectionNameKeyPath:@"day" cacheName:@"Events"];

用 nil 替换 @"Events"。

于 2015-01-10T13:20:12.293 回答