NSFetchedResultsController 在更新后看不到新的插入/删除获取的值

2024-01-08

在阅读了数十个类似的问题后,我想以这样的说法开始:“我确实设置了 NSFetchedResultsController 的委托,但它不起作用。”。

所以我有一个简单的 TableViewController,其单元格填充有 NSFetchedResultsController。这是 FRC 初始化代码:

@property (strong, nonatomic) NSFetchedResultsController *frc;

...

- (NSFetchedResultsController *)frc
{
    if (!_frc)
    {
        NSError *error = nil;
        NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:e_product];
        request.sortDescriptors = [NSArray arrayWithObjects:
                               [NSSortDescriptor sortDescriptorWithKey:@"product_group.product_group_name" ascending:YES],
                               [NSSortDescriptor sortDescriptorWithKey:f_product_name ascending:YES],
                               nil];
        _frc = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:[DTGGlobalSettings sharedInstance].moc sectionNameKeyPath:@"product_group.product_group_name" cacheName:nil];
        _frc.delegate = self;
        [_frc performFetch:&error];
        if (error)
        {
            NSLog(@"Error while fetching products: %@!", error.userInfo);
        }
    }

    return _frc;
}

我还使用一些调试标签实现了 NSFetchedResultsController 委托方法:

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
    // The fetch controller is about to start sending change notifications, so prepare the table view for updates.
    NSLog(@"controllerWillChangeContent");
    [self.tableView beginUpdates];
}


- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {

    UITableView *tableView = self.tableView;

switch(type) {

    case NSFetchedResultsChangeInsert:
        NSLog(@"didChangeObject - insert");
        [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
        break;

    case NSFetchedResultsChangeDelete:
        NSLog(@"didChangeObject - delete");
        [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
        break;

    case NSFetchedResultsChangeUpdate:
        NSLog(@"didChangeObject - update");
        [self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
        break;

    case NSFetchedResultsChangeMove:
        NSLog(@"didChangeObject - move");
        [tableView deleteRowsAtIndexPaths:[NSArray
                                           arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
        [tableView insertRowsAtIndexPaths:[NSArray
                                           arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
        break;
}
}


- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id )sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {

switch(type) {

    case NSFetchedResultsChangeInsert:
        NSLog(@"didChangeSection - insert");
        [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
        break;

    case NSFetchedResultsChangeDelete:
        NSLog(@"didChangeSection - delete");
        [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
        break;
}
}


- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
// The fetch controller has sent all current change notifications, so tell the table view to process all updates.
NSLog(@"controllerDidChangeContent");
[self.tableView endUpdates];
}

在我的导航栏中,我有刷新按钮,其功能是启动产品目录方法,该方法执行以下操作: 1.从远程MySQL服务器获取产品 2. 如果具有 ID 的产品不存在 - 创建它并填写所有字段 3. 如果存在,则根据获取的值更新所有字段

在第 2 行和第 3 行之后,商店被保存。 我对应用程序中的所有 CoreData 操作使用单个 NSManagedObjectContext。

当我第一次启动应用程序时,TVC 是空的,因为尚未获取任何产品。当我按“刷新”时,将获取新产品并将其插入到 ManagedObjectContext 中,但 NSManagedObjectContext 没有看到/听到任何更改:没有调用委托方法,因此没有新行添加到 TVC。 当我重新启动应用程序时,新产品会毫无问题地提取到 TVC 中。

如果我在有一些产品时再次按刷新按钮,则在短暂延迟后它们都会消失。一些调试向我表明,如果在更新实体的字段(实际上值相同)并保存商店后发生。这次的委托方法就像一个魅力,对于每个更新和保存的实体控制器:didChangeObject:atIndexPath:forChangeType:newIndexPath 都通过 forChangeType = NSFetchedResultsChangeDelete 调用。

问题#1:为什么 NSFetchedResultsController 在不重新启动应用程序的情况下看不到插入的实体? 问题#2:为什么 NSFetchedResultsController 将已获取的实体标记为“不存在”(?)并在存储保存后将它们从 TVC 中删除?

我将不胜感激任何帮助和想法,上周整个星期都在与这个问题作斗争;(

UPD1(对于乔迪):以下是一些细节。我使用自定义类 DTGGlobalSettings 在应用程序中共享一些变量。这就是我初始化其sharedInstance属性的方式:

+(DTGGlobalSettings *)sharedInstance
{
    static DTGGlobalSettings *myInstance = nil;

    if (nil == myInstance)
    {
        myInstance = [[[self class] alloc] init];
        // set values here
        // try to acces MOC to init CoreData 
        [myInstance moc];        
        myInstance.baseURL = @"http://local.app/";
}
return myInstance;
}

为了初始化 CoreData 堆栈,我使用了 Apple 文档中的示例,因为出于某种原因,我在创建新项目时没有看到“使用 CoreData”复选框。我确信我以前在 Xcode 中见过它,但现在我没有;( (Xcode 4.4.1):

#pragma mark Core Data stack

- (NSManagedObjectContext *) moc {

if (_moc != nil) {
    return _moc;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
    _moc = [[NSManagedObjectContext alloc] init];
    [_moc setPersistentStoreCoordinator: coordinator];
}
return _moc;
}


- (NSManagedObjectModel *)managedObjectModel {

if (_managedObjectModel != nil) {
    return _managedObjectModel;
}
_managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];    
return _managedObjectModel;
}


- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {

if (_persistentStoreCoordinator != nil) {
    return _persistentStoreCoordinator;
}
NSURL *storeUrl = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
storeUrl = [storeUrl URLByAppendingPathComponent:DOC_NAME];

NSError *error;
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];

if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:nil error:&error]) {
    NSLog(@"Error adding a store to the coordinator: %@, %@", error, error.userInfo);
}        
return _persistentStoreCoordinator;
}

-(void)saveDataStore
{
    NSError *error;
    if (![self.moc save:&error]) NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
}

然后,DTGGlobalSettings 的“moc”(ManagedObjectContext)属性将在应用程序中需要访问 CoreData 的任何地方使用。

现在进入第二部分,更新数据库。我从远程 Web 服务器获取一些 JSON 格式的新实体,遍历生成的字典并为请求结果中找到的每个实体调用 createFromDictionary 方法。这是代码:

+(Product *)createFromDictionary:(NSDictionary *)entityData inContext:(NSManagedObjectContext *)moc performUpdate:(BOOL)update
{
Product *result;
if (update)
{
    NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:e_product];
    request.predicate = [NSPredicate predicateWithFormat:@"%K = %@", f_product_id, [entityData objectForKey:f_product_id]];
    result = [[DTGGlobalSettings sharedInstance].moc executeFetchRequest:request error:nil].lastObject;
    if (!result)
    {
        NSLog(@"Error updating Product ID %@! Cannot fetch entity.", [entityData objectForKey:f_product_id]);
        return nil;
    }
} else
{
    result = [NSEntityDescription insertNewObjectForEntityForName:e_product inManagedObjectContext:[DTGGlobalSettings sharedInstance].moc];
}

result.product_id = [[DTGGlobalSettings sharedInstance].numFormatter numberFromString:[entityData objectForKey:f_product_id]];
result.product_image = [NSData dataWithContentsOfURL:[NSURL URLWithString:[[DTGGlobalSettings sharedInstance].baseURL stringByAppendingString:[entityData objectForKey:f_product_image]]]];
result.product_name = [entityData objectForKey:f_product_name];

return result;
}

当我用完所连接的实体时,我调用 [[DTGGlobalSettings sharedInstance] saveDataStore] (见上文)。此时,TVC 中的现有行(如果有)消失。如果我添加一些新实体,在保存时什么也不会发生,即 TVC 不会更新其行。


事实上,我认为你的第一个预编辑帖子已经包含了所有必要的信息。我只是没有读它(我不喜欢一直向右滚动阅读长行代码,有时只是不这样做 - 我的错)。

您的问题似乎与您的 FRC 排序描述符有关。

FRC 不能很好地保持关系排序描述符的更新。

有些人认为它就是这样设计的。我认为这是一个错误。

看这个帖子更改托管对象属性不会触发 NSFetchedResultsController 更新表视图 https://stackoverflow.com/questions/12370521/changing-a-managedobject-property-doesnt-trigger-nsfetchedresultscontroller-to/12379824#12379824就我而言。希望您会发现与您的案例的相似之处。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

NSFetchedResultsController 在更新后看不到新的插入/删除获取的值 的相关文章

随机推荐

  • Cordova 视频编辑器插件 InvalidOutputFormatException

    我在用着科尔多瓦插件视频编辑器 https www npmjs com package cordova plugin video editor处理以前录制的视频 该插件开始转换 但由于某种原因失败 我得到的错误是这样的 net yprest
  • 该程序集是由比当前加载的运行时更新的运行时构建的,无法加载

    我收到此错误 无法加载文件或程序集 Twitterizer2 Asynchronous 或其中之一 它的依赖项 该程序集是由比 当前已加载运行时且无法加载 但我已经从我的引用中删除了 twitterizer2 Asynchronous 库
  • 如何管理服务器上的数据库连接?

    我的 Web 应用程序中的数据库连接存在严重问题 由于我对单例数据库类的整个应用程序使用单个数据库连接 因此如果我尝试并发数据库操作 两个用户 数据库将回滚事务 这是我使用的静态方法 所有线程 servlet 都调用静态 Database
  • 当单元格更改时,VBA 运行宏,但如果通过宏则不运行

    好吧 我不确定这是否容易实现 但我会尝试 如果单元格发生更改 我使用此子程序来执行一些宏 Private Sub Worksheet Calculate Dim target As Range Set target Range b4 If
  • 将蛇形字符串转换为标题大小写

    我有以下蛇形变量big animal我想将其转换为Big Animal 我的方法是str gt str replace w g g gt g 1 toUpperCase 但我不断得到bigAnimal 但我想保留空格并将第一个字母大写 另一
  • C - 未定义的引用 - 是否有使用 -lm 编译的替代方法?

    我有一个很像这个问题的问题here https stackoverflow com questions 5248919 c undefined reference to sqrt其中错误是 未定义对 sqrt 的引用 我了解如何在编译时使用
  • Python 连接列表中的数组

    我有一个相同大小的数组列表 列表 z 包含 gt gt gt z 0 Out 24 array 27 56272878 952 8099842 3378 58996244 4303 9692863 gt gt gt z 1 Out 25 a
  • 如何在 Google Chrome 中暂时禁用 websocket?

    我想暂时禁用 Google Chrome 中的 websocket 来调试 javascript 以确保它适用于任何不支持 websocket 的浏览器 首先 我想说有更好的机制可以在无 websocket 环境中测试 JavaScript
  • 限制对 ASP.Net MVC 站点的匿名访问的问题

    每当我限制 MVC 站点中的匿名访问时 我都会收到 404 错误 应用程序中的服务器错误 无法找到该资源 描述 HTTP 404 您正在查找的资源 或其依赖项之一 可能已被删除 名称已更改或暂时不可用 请检查以下 URL 并确保其拼写正确
  • 跨不同程序开发的库的 Subversion 存储库布局

    我负责几个 相当小的 程序 它们通过不同的库共享大量代码 我想知道开发不同程序 和库 的最佳存储库布局是什么 并使库在所有程序之间保持同步 为了便于讨论 我们假设有两个带有两个库的程序 Program1 Library1 Library2
  • 检查文件是否存在的最快方法[重复]

    这个问题在这里已经有答案了 我使用的方法只是尝试 fopen 要检查的文件 does file exist char fname 999 whatever constructed during execution FILE fp NULL
  • sql.Identifier 不带引号

    我在网上搜索 sql Identifier without quoting 并且这个帖子 https stackoverflow com questions 43877210 how to remove the quotes from a
  • R 闪亮登录黑客

    在尝试了 RStudio Shiny Pro Server 的评估后 我对登录 身份验证机制不太感兴趣 因为它们不是管理客户端访问闪亮应用程序的用户帐户的简单机制 因此 我试图在 Shiny 中创建自己的登录机制 除了在shinydashb
  • .NET 客户端编程中出现异常“AMQP 操作被中断”(代码=406)

    我有一个 2 8 2 RabbitMQ 服务器和一个 2 8 2 客户端 dll 有声明队列并获取消息的代码 它工作正常 所有参数都正确 IModel channel null ConnectionFactory factory new C
  • Windows 工作流程 4.0 InstancePersistenceCommand 错误

    我有一个 wcf 工作流程 其中有三个按顺序排列的接收活动 IE 1 接收申请 2 经理1批准 3 最终经理批准 我的问题是 我能够使用客户端应用程序中的工作流程并调用第一个 接收应用程序活动 但是当我尝试调用第二个 manager1 批准
  • Android 中的轮播动画

    请参阅下面的屏幕 我尝试使用封面流来实现此动画 就像我们作为轮播动画一样 但我没有得到与屏幕中所示相同的效果 如果有人做过这种类型的动画 请将代码片段发送给我 我前段时间在我的应用程序中遇到了类似的问题 虽然我没有处理过您在图像右下角显示的
  • 在 R 中的同一张图上绘制多列[重复]

    这个问题在这里已经有答案了 我有以下数据框 A B C D Xax 0 451 0 333 0 034 0 173 0 22 0 491 0 270 0 033 0 207 0 34 0 389 0 249 0 084 0 271 0 54
  • RxJava2 + Room:clearAllTables() 调用后数据未插入数据库

    成功后在我的Android应用程序中login我将会话信息保存在 Room 中 然后从 BE 检索用户信息并保存它 一切正常 我可以看到数据库表中保存的信息 When 用户注销从应用程序中 所有表都通过 appDatabase clearA
  • 如何制作撤消/重做功能

    我想添加一个undo redo我的脚本中的函数 我环顾四周 看到了一些建议 其中大多数建议使用command pattern 该函数必须在一页上运行 重新加载页面后 该函数必须能够redo undo最后的事情 我不知道命令模式是如何工作的
  • NSFetchedResultsController 在更新后看不到新的插入/删除获取的值

    在阅读了数十个类似的问题后 我想以这样的说法开始 我确实设置了 NSFetchedResultsController 的委托 但它不起作用 所以我有一个简单的 TableViewController 其单元格填充有 NSFetchedRes