当我从单独的视图控制器中删除核心数据实体时,为啥会调用 UITableView 方法?

Posted

技术标签:

【中文标题】当我从单独的视图控制器中删除核心数据实体时,为啥会调用 UITableView 方法?【英文标题】:Why are UITableView methods being called when I delete CoreData Entities from a separate viewController?当我从单独的视图控制器中删除核心数据实体时,为什么会调用 UITableView 方法? 【发布时间】:2014-01-17 03:51:19 【问题描述】:

我有一个基于 tabBarViewController 构建的 ios 应用程序。该应用程序利用Restkit 从持久化在CoreData 中的Restful Web 服务中提取数据。如果用户想要注销应用程序,我有一个注销按钮,该按钮触发删除 CoreData 实体中所有对象的方法。应用程序中的主/主页选项卡是UICollectionView。第二个选项卡有一个UITableView,最后一个选项卡有一个包含两个单元格的静态表。最后一个选项卡中的一个单元格允许用户退出应用程序。

我偶然注意到,当我注销时,当我删除与它们相关的实体时,我打开的前一个 viewController 的 numberOfSectionsnumberOfRows 方法会被触发。例如,我的collectionView 填充了Gist 实体中持久保存的数据。如果用户正在查看collectionView 并导航到设置选项卡并选择注销,那么我的deleteAllEntitiesForName 方法将被调用。当该方法被告知删除Gist 实体中的对象时,出于某种原因,在collectionView 的viewController 中调用了numberOfSectionsnumberOfRows 方法!如果用户从那里导航,UITableViewController 中也会发生同样的情况。

为什么当我只是清除数据时,来自完全独立的视图控制器的方法会被触发?

我正在使用NSLog 来通知这些功能正在被触发。

更奇怪的是,如果我连续登录和注销,则每次注销时都会调用一次方法。这是来自我的控制台的证明....

编译后第一次注销并在模拟器中运行:

2014-01-16  delete Gist
2014-01-16  Check numberOfSectionsInCollectionView
2014-01-16  Check numberofItemsInSection
2014-01-16  delete ActivityData
2014-01-16  delete FollowActivityData
2014-01-16  delete InsertNodes

在模拟器中运行应用程序时登录并退出:

2014-01-16  delete Gist
2014-01-16  Check numberOfSectionsInCollectionView
2014-01-16  Check numberofItemsInSection
2014-01-16  Check numberOfSectionsInCollectionView
2014-01-16  Check numberofItemsInSection
2014-01-16  delete ActivityData
2014-01-16  delete FollowActivityData
2014-01-16  delete InsertNodes

这是我用来清除实体中持久数据的方法。

- (void) deleteAllEntitiesForName:(NSString*)entityName 
    NSEntityDescription *entityDescription = [NSEntityDescription entityForName: entityName inManagedObjectContext:managedObjectContext];
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    [request setEntity:entityDescription];
    NSError *error = nil;
    NSArray *array = [managedObjectContext executeFetchRequest:request error:&error];
    if (array != nil) 
        for(NSManagedObject *managedObject in array) 
            [managedObjectContext deleteObject:managedObject];
        
        error = nil;
        [managedObjectContext save:&error];
    


我不能说我注意到应用程序的运行方式有任何问题。我已经确认从核心数据实体中清除了所有数据。但我担心我可能在这里做错了什么。特别令人担忧的部分是,每次用户注销时都会触发一次方法。

有人知道这里发生了什么吗?我应该担心吗?我该如何处理?感谢您的意见!

我相信我从这里得到了deleteAllEntitiesForName 方法Delete/Reset all entries in Core Data?

===========更新=============

collectionView 和 tableView 使用 FetchedResultsController 填充。这是我的实现以及对我的一些发现的评论。

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

    NSLog(@"CHECK didChangeObject");
    //THIS METHOD IS TRIGGERED FIRST AFTER THE DELETE HAS STARTED.
    //IT IS TRIGGERED ONCE FOR EVERY CELL IN THE COLLECTION OR ONCE FOR EVERY ROW IN THE TABLE


- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller

    NSLog(@"CHECK didChangeContent");
    //THIS METHOD IS TRIGGERED NEXT.  IT IS TRIGGERED ONCE AFTER ALL THE OBJECT DATA WAS DELETED IN THE METHOD ABOVE.


- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
    NSLog(@"Check numberOfSectionsInCollectionView");
    return [[self.fetchedResultsController sections] count];
    //THIS METHOD IS THEN TRIGGERED FOLLOWED BY THE FETCHED RESULTS CONTROLLER


- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section 
    NSLog(@"Check numberofItemsInSection");
    id <NSFetchedResultsSectionInfo> sectionInfo = [self.fetchedResultsController sections][section];
    return [sectionInfo numberOfObjects];
    //FOLLOWING THE FRC THIS METHOD IS CALLED AND ONCE AGAIN THE FRC IS TRIGGERED


- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath 
    static NSString *CellIdentifier = @"Cell";
    //THIS IS WHERE GUTS OF THE CELLS ARE POPULATED.  I LEFT IT OUT FOR BREVITY.
    //THIS METHOD IS NEVER TRIGGERED WHEN CLEARING OUT THE CORE DATA.

【问题讨论】:

只是使用 Core Data 得到的许多奇怪的副作用之一。它似乎坚持一切。我们已经或正在将我们所有的东西从 Core Data 转移到 FMDB。 我个人怀疑这与核心数据有关,更可能是您如何实现这些视图。有没有机会在 github 或类似项目上查看和调试? 这不是使用 Core Data 的“许多奇怪的副作用之一”。您的实现中的某些内容告诉 collectionView / tableView 某些内容发生了变化。 Core Data 不会神奇地为您做到这一点。 【参考方案1】:

您可能(猜测,因为您没有说)使用 FetchedResultsController 作为表的数据源。

如果是这样,请注意 FRC 对象是“活动的”,因为它们主动响应其数据(它们链接到的核心数据内容)的变化。如果您从他们下面更改数据,他们会注意到并做出响应。如果你将它们链接为 UITableViews 的数据源,它们会告诉表格视图。

如果您愿意发布一些关于您的数据如何从核心数据链接到表格视图的详细信息,我们可以更好地帮助您了解核心数据更改为何会向表格视图生成消息。

【讨论】:

确实,我使用 FRC 作为 collectionView 和 tableView 的数据源。我会更新我的问题以反映这一点。 Bill 我绝对同意你所说的 FRC 的积极性。阅读您的声明后,我添加了更多日志来监控 FRC 的活动。我发现每次删除支持对象数据时都会触发 FRC 及其支持方法(特别是 didChangeObject...atIndexPath...)。现在来回答这个问题。这是一个问题吗?似乎它的行为方式应有尽有。 我认为,根据限制理解,这对您的情况来说不是问题。使用 UINavigationControllers 和 UITabBarControllers,您可以拥有仍然“活跃”但不在屏幕上的 VC。通知被发送到这些对象,并且它们相应地更新它们的状态。但它们在屏幕外,所以没有造成真正的伤害(只是更新内存中的对象)。唯一的危害是,如果您有一些东西正在监视 UITableView 上的状态变化,这真的非常非常不寻常,而且您会自己编写一些东西。 很公平,我会接受的。我仍然有每次用户注销时触发一次方法的问题。显然我在这里忽略了一个内存管理问题。如果您或其他任何人意识到为什么会发生这种情况,请编辑您的解决方案以反映这一点!谢谢比尔! 你可以拥有所有你想要的问题。 :-) 但它是 FetchedResultsController 的本质,它应该在每次它包含的对象被修改时告诉表视图。动态监控和更新核心数据对象是它的全部目的。如果您希望它在您从 Core Data 存储中删除对象时不执行操作,那么您需要在开始对存储的 Core Data 对象进行修改之前断开/擦除 FRC。

以上是关于当我从单独的视图控制器中删除核心数据实体时,为啥会调用 UITableView 方法?的主要内容,如果未能解决你的问题,请参考以下文章

当我从另一个视图控制器调用时,为啥我的表视图为零?

将 TextField 条目从模态视图控制器保存到核心数据单独的实体

在 macOS 上的 SwiftUI 列表视图中选择和删除核心数据实体

核心数据 - 不能存储两个单独的实体

iOS:删除核心数据中具有一对多关系的实体

为啥 EF 在分离时会删除子实体?