我有一个包含子类化UICollectionViewCells的UICollectionView。
这些单元格上具有向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;
});
}];
}
不要保留对单元格的引用-保留对索引路径的引用,并在您关注的索引路径处询问单元格的收集视图,例如:
[[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
要进行更新,而且还要保证在发生回调时更新表示该单元格的单元格,因此您不必不会干扰其他细胞。您看到的问题的根源是集合视图会重复使用单元格,因此在任何给定时间,单元格都可以在完全不同的索引路径上表示数据。
完全无关,但你并不需要做object
一个__block
变量,因为你永远不改变变量本身的价值。与相同cell
,尽管更改之后您仍然不会在代码块中使用它。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句