gpt4 book ai didi

ios - NSFetchedResultsController 发现错误数量的对象

转载 作者:行者123 更新时间:2023-12-01 16:06:23 25 4
gpt4 key购买 nike

我看到 NSFetchRequest 返回不同数量的对象的情况,这取决于它是直接通过 NSManagedObjectContext 执行还是作为构建 NSFetchedResultsController 的一部分执行。

示例代码:

- (void)setupResultsController {
NSError *error = nil;
NSManagedObjectContext *ctx = [[DataManager sharedInstance] mainObjectContext];

// Create a fetch request and execute it directly
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];

NSEntityDescription *entity = [Song entityInManagedObjectContext:ctx];
[fetchRequest setEntity:entity];
[fetchRequest setFetchBatchSize:20];

NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"section" ascending:YES];
NSSortDescriptor *nameDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
NSArray *sortDescriptors = @[sortDescriptor, nameDescriptor];

[fetchRequest setSortDescriptors:sortDescriptors];
NSArray *debugResults = [ctx executeFetchRequest:fetchRequest error:&error];
NSLog(@"Count from context fetch: %lu", (unsigned long)debugResults.count);

// Use the request to populate a NSFetchedResultsController
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc]
initWithFetchRequest:fetchRequest
managedObjectContext:ctx
sectionNameKeyPath:@"section"
cacheName:@"Detail"];
[aFetchedResultsController performFetch:&error];
NSLog(@"Count from results controller fetch: %lu", (unsigned long)[[aFetchedResultsController fetchedObjects] count]);

_songResultsController = aFetchedResultsController;
}

在日志消息中执行上述结果:

2020-01-10 11:05:07.892772-0500 asb7[12985:105052] 从上下文获取计数:10

2020-01-10 11:05:07.893259-0500 asb7[12985:105052] 从结果 Controller 获取计数:9

两次获取的区别在于 NSFetchedResultsController 缺少最近添加的对象。一个极端奇怪的地方是,在运行应用程序一些看似随机的次数后,计数开始一致并获取新对象。

编辑:

如果我将 nil 作为缓存名称传递,或者如果我删除第二个排序描述符,结果会变得一致。显然,这些会导致不良的行为变化,但可能是线索。

NSFetchedResultsController 似乎将过时的缓存视为有效。更改排序描述符会使缓存失效,但是更新持久存储文件应该会使它失效,但在这种情况下显然不会。

经过更多试验后,我有了一个解释……如果不是解决方案的话。添加新对象不会更改我的 .sqlite 文件的修改日期。它更新了 .sqlite-shm 和 .sqlite-wal 但我猜在判断是否使用缓存时不会考虑这些。在终端 session 中使用 touch 可以在下次启动时解决问题。

(Xcode 10.1、macOS 10.13.6、部署目标 10.3、iOS 12.1 模拟器和 10.3.2 设备)

另一个编辑:

我已经在 https://github.com/PhilKMills/CacheTest 上传了一个演示问题的压缩项目目录。

我得到的是:第一次运行,两次提取都有 3 条记录;第二次运行,6 和 3。我认为这完全有可能取决于我的特定软件版本,但我目前无法升级。其他人的结果将是最有趣的。

注意:如果没有分配 FRC 委托(delegate),则不会出现此问题。

最佳答案

我怀疑问题与 FRC 缓存的使用有关,但我不确定为什么会这样。因此,一种解决方法是放弃使用 FRC 缓存。然而,这并不理想。

经过 OP 的进一步实验,问题似乎与与持久存储关联的 .sqlite 文件上的时间戳有关。通过推断(*),如果 FRC 检测到时间戳已更改,它会意识到其缓存可能已过时,并重建它 - 从而检测到新添加的对象。但是,因为 CoreData 默认使用 SQLite 的“WAL 日志模式”(参见 herehere),数据库更新不会写入 .sqlite 文件,而是写入一个单独的 .sqlite-wal 文件:.sqlite 文件上的时间戳因此不会更改,即使数据库已更新。 FRC 继续使用它的缓存,不知道额外的对象(或者实际上其他的变化)。

因此,第二种解决方法是放弃使用 SQLite 的 WAL 日志模式。这可以通过在加载持久存储时指定所需的日志模式来实现,使用

NSSQLitePragmasOption:@{@"journal_mode":@"DELETE"}

参见 here .

(*) 事实上,这是记录在案的 here :

“the controller tests the cache to determine whether its contents are still valid. The controller compares the current entity name, entity version hash, sort descriptors, and section key-path with those stored in the cache, as well as the modification date of the cached information file and the persistent store file.”

关于ios - NSFetchedResultsController 发现错误数量的对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59685471/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com