4

我有一个 UICollectionView,它由子类 UICollectionViewCells 组成。

这些单元格上有向 API 发出异步请求的按钮。在一种情况下,我有一个“心脏”按钮。点击此按钮将禁用按钮并异步进行 API 调用并传入一个块以用作回调。当调用成功返回时,按钮将更新为不同的状态。

问题是,当调用块中的代码时,对单元格的引用似乎会丢失或更改。所以,坏事发生了,比如当单元格滚动离开屏幕时,按钮的状态永远不会更新,并且只要重新使用该单元格,按钮就会保持禁用状态。

这里的最佳做法是什么?

- (void)didTapHeart:(id)sender event:(id)event {
NSSet *touches = [event allTouches];
UITouch *touch = [touches anyObject];
CGPoint currentTouchPosition = [touch locationInView:self.collectionView];
NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:currentTouchPosition];

__block MyObject *object = [myObjects objectAtIndex:indexPath.row];
__block CollectionViewCell *cell = (CollectionViewCell *)[sender superview];

cell.btnHeart.enabled = NO;

[[ApiSingleton defaultApi] like:object success:^{
    dispatch_async(dispatch_get_main_queue(), ^{
        cell.btnHeart.enabled = YES;
        object.isLiked = YES;
        object.likeCount++;
        [cell setLiked:YES];
    });

} failure:^(NSDictionary *error) {

    dispatch_async(dispatch_get_main_queue(), ^{
        [cell setLiked:NO];
        cell.btnHeart.enabled = YES;
        object.isLiked = NO;
    });
}];

}

4

2 回答 2

4

不要保留对单元格的引用 - 保留对索引路径的引用并在您关注的索引路径处向集合视图询问单元格例如:

[[ApiSingleton defaultApi] like:object success:^{
    dispatch_async(dispatch_get_main_queue(), ^{
        CollectionViewCell *blockCell = [self.collectionView cellForItemAtIndexPath:indexPath];
        blockCell.btnHeart.enabled = YES;
        object.isLiked = YES;
        object.likeCount++;
        [blockCell setLiked:YES];
    });

} failure:^(NSDictionary *error) {

    dispatch_async(dispatch_get_main_queue(), ^{
        CollectionViewCell *blockCell = [self.collectionView cellForItemAtIndexPath:indexPath];
        [blockCell setLiked:NO];
        blockCell.btnHeart.enabled = YES;
        object.isLiked = NO;
    });
}];

由于在这种情况下cellForItemAtIndexPath:返回代表的单元格object,或者nil如果当时屏幕上不存在这样的单元格,您不仅更新object而且保证在回调发生时更新代表它的单元格,因此您不会t 干扰其他细胞。您看到的问题的根源是集合视图重新使用了单元格,因此在任何给定时间,单元格都可以在完全不同的索引路径上表示数据。

完全不相关,但您不需要创建object变量__block,因为您永远不会更改变量本身的值。与 相同cell,尽管在此更改之后您无论如何都不会在块中使用它。

于 2013-11-06T19:06:39.733 回答
0

斯威夫特 5

1> 保留 indexPath 的引用。

1> Declare the index path variable

   var referenceIndex: IndexPath?

2> set the indexPath in cellForItemAt


     func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
      referenceIndex = indexPath
}

2> 然后得到像下面这样的单元格。

if let cell = self.collectionView.cellForItem(at: referenceIndex) as? CollectionViewCell {
      // Do the expected functionality   
}
于 2021-06-21T09:22:20.470 回答