【问题标题】:NSFetchedResultsController crashing on performFetch: when using a cacheNSFetchedResultsController 在 performFetch 上崩溃:使用缓存时
【发布时间】:2011-02-12 04:17:05
【问题描述】:

我使用 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"];

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

【问题讨论】:

    标签: iphone objective-c core-data nsfetchedresultscontroller


    【解决方案1】:

    Xcode 7(beta 4)仍然会出现异常:

    你非法改变了 NSFetchedResultsController 的 fetch 请求,它的谓词,或者它的排序描述符,没有任何一个 禁用缓存或使用 +deleteCacheWithName:

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

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

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

    问题仍然可以修复如下,使用一种或另一种以下方法:

    • 在 AppDelegate 的 application didFinishLaunchingWithOptions 方法中,添加以下 Swift NSFetchedResultsController.deleteCacheWithName(nil) 或 Objective-C [NSFetchedResultsController deleteCacheWithName:nil]; 代码。这会清除损坏的缓存。
    • 在模拟器中,从模拟器菜单中选择重置内容和设置。这可以解决问题,但您会丢失测试数据

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

    【讨论】:

      【解决方案2】:

      我通过 Ray Wenderlich forums 发现

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

      所以,我的情况是这样的:

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

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

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

      请注意来自调试器的警告

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

      根本不会捕获这种情况,因为您更改的不是请求、谓词或排序描述符,而是更准确地说可以描述为在获取过程中更改了结果集.

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

      【讨论】:

        【解决方案3】:
        NSFetchedResultsController *fetched = [[NSFetchedResultsController alloc] initWithFetchRequest:fetch managedObjectContext:self.managedObjectContext sectionNameKeyPath:@"day" cacheName:@"Events"];
        

        将@"Events" 替换为 nil。

        【讨论】:

          【解决方案4】:

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

          [NSFetchedResultsController deleteCacheWithName:@"Name"];
          

          【讨论】:

            【解决方案5】:

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

            【讨论】:

              【解决方案6】:

              直接来自NSFetchedResultsController 的文档:

              修改获取请求

              您不能简单地更改获取请求 修改结果。如果你想改变获取请求,你 必须:

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

              2. 更改获取请求。

              3. 调用 performFetch:

              【讨论】:

                【解决方案7】:

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

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

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

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

                【讨论】:

                  【解决方案8】:

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

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

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

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

                  [NSFetchedResultsController deleteCacheWithName:nil];
                  

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

                  【讨论】:

                  • [NSFetchedResultsController deleteCacheWithName:nil];为我工作......以前我在做 deleteCachWithName:someName。当我将 someName 切换为 nil 时,工作就像一个魅力。那时意识到我创建的 fetchRequest 使用的缓存名称与我删除的不同......最后,我修正了我的错字并使用缓存名称显式删除,但 nil 也有效,原因很明显。
                  【解决方案9】:

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

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

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

                  【讨论】:

                  • 有关更多详细信息,请查看 NSFetchedResultsController 的文档。
                  • nil 为我工作 - 从 3.x 到 4.x 的应用程序引发了同样的错误。
                  • [OT] 哈哈。仍然从 4yo 的答案中获得代表。[/OT]
                  • 我不相信将缓存设置为 nil 是最佳答案。那么我们不是只是禁用所有缓存,放弃性能吗?
                  【解决方案10】:

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

                  【讨论】:

                    【解决方案11】:

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

                    【讨论】:

                      【解决方案12】:

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

                      - (void)applicationWillTerminate:(UIApplication *)application {
                          [NSFetchedResultsController deleteCacheNamed:@"Events"];
                          //etc
                      }
                      

                      【讨论】:

                      • 删除应用程序只会导致相同的循环。终止时删除缓存不会完全破坏拥有缓存的目的吗?
                      • @Oliver:它破坏了缓存的部分用途(我很确定缓存还可以通过消除提取来提高运行时的性能)。如果它有效,这是一个非常笨拙的解决方案,但是NSFetchedResultsController 仍然(从 SDK 3.1 开始)有很多错误(例如,我遇到了它不正确地缓存节标题的问题)。我没有发现您发布的代码有任何问题,因此在您找出实际问题之前,这可能是一个临时解决方案(无论是在您的代码中还是在NSFetchedResultsController)。
                      • 我所做的是根据查询建立一个缓存名称。就我而言,通常是:@"%@-%@-%@", [entity name], queryId, sortOption.
                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2016-05-04
                      相关资源
                      最近更新 更多