UICollectionView 在包含标题时不会重新加载项目

Posted

技术标签:

【中文标题】UICollectionView 在包含标题时不会重新加载项目【英文标题】:UICollectionView doesn't reload items when containing a header 【发布时间】:2012-10-04 00:15:05 【问题描述】:

编辑:最初的问题是错误的,所以有些内容可能有点不相关。但可能会让你对我做事的方式有更好的印象。

NSFetchedResultsController 有一个非常奇怪的问题。首先,我将描述我的应用程序的当前情况。我有多个AlbumPhoto 实体,它们都是抽象类AbstractItem 的子类。

在我的AlbumViewController 中,我使用NSFetchedResultsController 来获取当前superAlbum 的所有AbstractItem。像这样:

- (NSFetchedResultsController *)fetchedResultsController 
    if (!fetchedResultsController ) 
        NSFetchRequest *request = [[NSFetchRequest alloc] init];

        [request setEntity:[NSEntityDescription entityForName:@"AbstractItem"
                                       inManagedObjectContext:managedObjectContext]];

        [request setSortDescriptors:@[
         [NSSortDescriptor sortDescriptorWithKey:@"type" ascending:YES],
         [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES],
         [NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]
        ]];

        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"superAlbum = %@", self.parentAlbum];
        [request setPredicate:predicate];

        NSFetchedResultsController *newController = [[NSFetchedResultsController alloc] initWithFetchRequest:request
                                                                                        managedObjectContext:managedObjectContext
                                                                                          sectionNameKeyPath:@"type"
                                                                                                   cacheName:nil];

        newController.delegate = self;

        self.fetchedResultsController = newController;
    

    return fetchedResultsController;

当我选择Album 时,AlbumViewController 的另一个实例被启动并推送到我的导航控制器上。在这种情况下,parentAlbum 被设置为选定的对象。

现在,当我使用以下代码添加新的Album 时,会出现错误。

Album *album = (Album *)[Album itemInManagedObjectContext:self.managedObjectContext];
album.name = @"Test album";
album.superAlbum = self.parentAlbum;

NSError *error;
BOOL success = [self.managedObjectContext save:&error];

if (!success) 
    NSLog(@"Error: %@", error);

parentAlbum 对象的 NSFetchedResultsChangeUpdate 类型调用方法 controller:didChangeObject:atIndexPath:forChangeType:newIndexPath:。当前的NSFetchedResultsController 中不存在那个。因此,当它尝试在集合视图中更新它时会失败。

如何将不在当前NSFetchedResultsController 中的对象用于通知?我该如何解决这个问题?

编辑: 发布问题后,我意识到它实际上不是NSFetchedResultsController 通知错误的对象。但它会通知上一个(父)集合视图中的对象,但它会通知它自己的集合视图控制器。

但这可能只是问题所在;集合视图控制器在不可见时收到通知,看起来目前无法处理。我这样处理通知:

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath     
    switch (type) 
        case NSFetchedResultsChangeUpdate:
            [self.collectionView reloadItemsAtIndexPaths:@[indexPath]];
            break;
    

我很确定它以前可以正常工作。在迭代自上次提交以来所做的更改后,我让它再次工作。在我删除 UICollectionView 标头(补充视图)后,它再次起作用了。

所以:当我的UICollectionView 有标题并且当前不可见时,它无法更新项目。这是一个很难发现的问题,但是如何解决呢?认为这是一个非常奇怪的问题。

我得到的错误:

2012-10-04 11:54:21.148 PhotoLibrary[9195:c07] -[NSISObjectiveLinearExpression coefficientForVariable:]: unrecognized selector sent to instance 0x968bae0
2012-10-04 11:54:21.151 PhotoLibrary[9195:c07] CoreData: error: Serious application error.  Exception was caught during Core Data change processing.  This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification.  -[NSISObjectiveLinearExpression coefficientForVariable:]: unrecognized selector sent to instance 0x968bae0 with userInfo (null)
2012-10-04 11:54:21.156 PhotoLibrary[9195:c07] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSISObjectiveLinearExpression coefficientForVariable:]: unrecognized selector sent to instance 0x968bae0'
*** First throw call stack:
(0x2977012 0x1418e7e 0x2a024bd 0x2966bbc 0x296694e 0xcb06c3 0xcb569c 0xcbf88e 0x58c670 0x5945bd 0x29198fd 0x594605 0x29198fd 0x594605 0x29198fd 0x594605 0x5946c7 0x9cd53 0x5525ff 0x9ea5c 0x5522f7 0x565228 0x56231b 0x55ed4e 0x55edf0 0x8f56 0x1242c1a 0xbcddc9 0x29d10c5 0x292befa 0xb02482 0x11545f3 0x11ede5f 0x114fa26 0x115316e 0x55dc 0x85e5 0x4312c1 0x142c705 0x57920 0x578b8 0x118671 0x118bcf 0x117d38 0x8733f 0x87552 0x653aa 0x56cf8 0x20badf9 0x20baad0 0x28ecbf5 0x28ec962 0x291dbb6 0x291cf44 0x291ce1b 0x20b97e3 0x20b9668 0x5465c 0x26bd 0x25e5)
libc++abi.dylib: terminate called throwing an exception

【问题讨论】:

在保存托管对象上下文时,您是否得到任何错误信息?另外,itemInManagedObjectContext: 是什么?从异常来看,这是一个核心数据问题,而不是集合视图问题。 没有任何其他错误,但相册不会被保存,所以可能是 save 方法甚至没有被调用?方法itemInManagedObjectContext: 只是调用[NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:context] 并设置一些默认值(如creationDate)。 但是在[self.collectionView reloadItemsAtIndexPaths:@[indexPath]]; 之前一切正常,所以我想这并不是真正的核心数据问题。在集合视图中没有标题也可以正常工作。 打开异常断点,看看它是否会在它不喜欢的确切行上中断。 它正好在那条线上中断。我做了一个示例项目:cloud.h-dev.nl/1x1W2t2y3p0d 只需添加一个事件,点击它并添加另一个。当您删除标题时,它不会发生。 【参考方案1】:

我不知道这是解决方案还是变通方法,但是如果您在viewWillDisappear 中释放获取的结果控制器:

- (void)viewWillDisappear:(BOOL)animated

    [super viewWillDisappear:animated];
    self.fetchedResultsController = nil;

那么您的 ErrorTest 程序就不会再崩溃并且似乎可以正常工作了。

这避免了对当前不可见的集合视图的更新。

由于您已经在viewWillAppear 中访问 FRC:

- (void)viewWillAppear:(BOOL)animated 
    [super viewWillAppear:animated];
    // ...    
    NSError *error = nil;
    BOOL success = [self.fetchedResultsController performFetch:&error];
    // ...

由于 FRC 的惰性设置器功能,当视图再次可见时,FRC 将重新创建。

【讨论】:

但这实际上是一种更好的方法,对吧?因为它会在视图出现时获取结果。 虽然,一次获取可能比几次更新更重......所以当您返回到之前的视图控制器时,它可能不是重新获取的理想方法。 @GuidoH:正如我所说,这是一种解决方法。而且您的代码已经在viewWillAppear 中执行了performFetch。 - 实际上,在viewWillDisappear 中设置self.fetchedResultsController.delegate = nil 就足够了,以避免更新视图控制器,这样您就不必在viewWillAppear 中重新创建FRC。但是如果你再次在viewWillAppear 中设置代理,你也必须调用performFetch,因为FRC 不跟踪更改,而它没有代理。

以上是关于UICollectionView 在包含标题时不会重新加载项目的主要内容,如果未能解决你的问题,请参考以下文章

UICollectionView Cell 在选择时不会改变

重新加载 UICollectionView 时 UIActivityIndi​​cator 不会停止

UICollectionView 在调用 reloadData 时不会立即更新,而是在 30-60 秒后随机更新

UICollectionView invalidateLayout 不会在屏幕方向更改时触发 sizeForItem

嵌入式视图控制器中的 UICollectionView 不会调用 cellForItemAtIndexPath

当我在 iOS 14 上的 UITableView 单元格内使用 UICollectionView 时,不会调用 UICollectionView cellForItemAt