记录一次cell的block捕获model引发的bug

下面这段代码乍一看没什么问题,其实会造成cell.buyBtnClick 捕获model的问题,造成点击按钮model不是正确model的bug

bug代码:

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    QYMyCourseCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"QYMyCourseCell" forIndexPath:indexPath];
    QYMyHomeCourseSubjectModel*  subjectModel = [self.dataList safeObjectAtIndex:indexPath.section];
       QYMyHomeCourseModel*  model = [subjectModel.list safeObjectAtIndex:indexPath.item];
       cell.model = model;
       @weakify(self);
       if (!cell.buyBtnClick) {
           cell.buyBtnClick = ^{
               @strongify(self);
               NSString *name = model.title;
               [[[UIAlertView alloc] initWithTitle:nil message:name delegate:nil cancelButtonTitle:@"0k" otherButtonTitles:nil, nil] show];
           };
       }
    return cell;
}

来分析下这段代码:
由于block的实现是写在- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath,这个代理方法里面,
这个方法调用会很频繁,所以在cell的block的实现上加上 if (!cell.buyBtnClick) { .... } 的判断没有问题,可以避免block频繁创建的赋值,提升性能; 但是由于cell的复用机制,当列表中cell比较多时,cell循环利用,cell捕获的之前cell的model而不是当前的model.

正确的写法应该是,把model 作为cell的block的参数回调回来

@interface QYMyCourseCell : UICollectionViewCell
@property(nonatomic, strong) void (^buyBtnClick)(QYMyHomeCourseModel *model);
@end

@implementation DTMyCourseViewController
 @weakify(self);
    [self.buyBtn setBlockForControlEvents:UIControlEventTouchUpInside block:^(id _Nonnull sender) {
        @strongify(self);
        !self.buyBtnClick ? : self.buyBtnClick(self.model);
    }];
@end
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    QYMyCourseCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"QYMyCourseCell" forIndexPath:indexPath];
    QYMyHomeCourseSubjectModel*  subjectModel = [self.dataList safeObjectAtIndex:indexPath.section];
       QYMyHomeCourseModel*  model = [subjectModel.list safeObjectAtIndex:indexPath.item];
       cell.model = model;
       @weakify(self);
       if (!cell.buyBtnClick) {
           cell.buyBtnClick = ^(QYMyHomeCourseModel * _Nonnull cellModel) {
               @strongify(self);
               NSString *name = cellModel.title;
               [[[UIAlertView alloc] initWithTitle:nil message:name delegate:nil cancelButtonTitle:@"0k" otherButtonTitles:nil, nil] show];
           };
       }
    return cell;
}

这样cell中的按钮点击时,回调回来的,永远是当前cell的model.