美文网首页
deleteRowsAtIndexPaths 崩溃

deleteRowsAtIndexPaths 崩溃

作者: 希达like | 来源:发表于2018-05-08 20:59 被阅读0次
背景

公司项目有一个消息的列表页,点击自定义cell上的删除按钮执行删除操作

#import "MyCell.h"

、、、、、

-(void)rowDelete:(UIButton *)btn{
    if (self.delegate && [self.delegate respondsToSelector:@selector(deleteNewsBtnClicked:)]) {
        [self.delegate deleteNewsBtnClicked:self.buttonTag];
    }
}

#import "ViewController.h"

、、、、、、

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    MyCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
    if (!cell) {
        cell = [[MyCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"];
        cell.delegate = self;
    }
    cell.titleLab.text = self.dataSource[indexPath.row];
    cell.buttonTag = indexPath.row;
    return cell;
}

、、、、、、

- (void)deleteBtnClicked:(NSInteger)button{
    NSLog(@"----------正在删除:%zd行",button);
    [self.dataSource removeObjectAtIndex:button];
    //错误的写法:
 NSIndexPath* path =[NSIndexPath indexPathForRow:button inSection:0];
    NSMutableArray* deleteArray=[NSMutableArray arrayWithObject:path];
    [self.tableView deleteRowsAtIndexPaths:deleteArray withRowAnimation:UITableViewRowAnimationFade];
}
造成的后果
  • 崩溃 :如果所有cell在屏幕的高度范围内可以全部展示出来,这时候删除第一条数据,再删除最后一条数据,会造成崩溃,报错信息是数组越界
  • 删除数据不对:如果删除第一个数据后,接着删除第二条数据,会发现实际上是第三条数据被删除了
原因分析

执行deleteRowsAtIndexPaths只会重新执行numberOfRowsInSection方法,而cellForRowAtIndexPath不会重新执行,这使得每个cell的buttontag不变,不会根据删除后的dataSource重新赋值。这时候数据源已经减少,如果点击最后一行的删除按钮,必然会引起数组越界。
如果列表较长,删除数据时需要滑动,这时候就不会出现上述的问题,因为滑动会走cellForRowAtIndexPath方法,会使cell的buttontag属性值及时得到更新。

解决办法一

使用

- (void)deleteNewsBtnClicked:(NSInteger)button{
    NSLog(@"----------正在删除:%zd行",button);
    [self.dataSource removeObjectAtIndex:button];
    // 表格刷新
    [self.tableView reloadData];
}

采用这种方法的缺点就是:

  • 没有自带删除动画
  • reload会消耗更多资源
解决办法二(推荐)

将cell通过代理传出来,再通过cell找到其indexpath

#import <UIKit/UIKit.h>
@class MyCell;

@protocol LKLNewsDelegate <NSObject>
- (void)deleteNewsBtnClicked:(MyCell *)cell;
@end

@interface MyCell : UITableViewCell

@property (nonatomic, assign)id<LKLNewsDelegate>delegate;
@property(nonatomic,strong)UILabel *titleLab;

@end
#import "MyCell.h"
    、、、、、、
-(void)rowDelete:(UIButton *)btn{
    if (self.delegate && [self.delegate respondsToSelector:@selector(deleteNewsBtnClicked:)]) {
        [self.delegate deleteNewsBtnClicked:self];
    }
}
#import "ViewController.h"
       、、、、、
-(void)deleteNewsBtnClicked:(MyCell *)cell{
    NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
    [self.dataSource removeObjectAtIndex:indexPath.row];
    [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];    
}

这种方法的优点就是没有方法一的缺点 哈哈哈

相关文章

网友评论

      本文标题:deleteRowsAtIndexPaths 崩溃

      本文链接:https://www.haomeiwen.com/subject/ojowrftx.html