崩潰日志
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 1. The number of rows contained in an existing section after the update (2) must be equal to the number of rows contained in that section before the update (3), plus or minus the number of rows inserted or deleted from that section (0 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'
簡(jiǎn)單說(shuō)明一下這個(gè)崩潰造成的原因有兩種:
1、刷新section
2、move section
刷新section
UITableView調(diào)用刷新某一section,如下:
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade];
而在刷新某一section的時(shí)候,其他的seciton中對(duì)應(yīng)的row個(gè)數(shù)改變侥衬,從而導(dǎo)致崩潰。
下面可以附上一個(gè)簡(jiǎn)單的栗子,一個(gè)類(lèi)搞定的事就不給demo了哈:
#import "ViewController.h"
@interface ViewController () <UITableViewDelegate,UITableViewDataSource>
@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, strong) NSMutableArray *dataArray;
@property (nonatomic, strong) NSMutableArray *dataArray2;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.dataArray = [NSMutableArray arrayWithObjects:@1,@2,@3,nil];
self.dataArray2 = [NSMutableArray arrayWithObjects:@1,@2,@3,nil];
self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 300, 400)];
self.tableView.backgroundColor = [UIColor redColor];
self.tableView.delegate = self;
self.tableView.dataSource = self;
[self.view addSubview:self.tableView];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self.dataArray2 removeObjectAtIndex:0];
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade];
});
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 30;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 2;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (section == 0) {
return self.dataArray.count;
}
return self.dataArray2.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *testCell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:@"~~~~~UITableViewCell"];
testCell.backgroundColor = [UIColor blueColor];
return testCell;
}
@end
move cell
這邊主要是在UITableView進(jìn)行move section
的時(shí)候沒(méi)有注意就會(huì)造成該崩潰乾戏。簡(jiǎn)單說(shuō)明一下UITableView 的move sectionnnn
操作,由于move的時(shí)候沒(méi)有進(jìn)行刷新會(huì)導(dǎo)致一個(gè)問(wèn)題:section對(duì)應(yīng)的indexPath還是原本的值三热,UITableView沒(méi)有更新該值,所以需要自己去記錄indexPath的值。而在move的時(shí)候indexPath的section其中一個(gè)值沒(méi)有更新自己記錄的值邢隧,多次move的時(shí)候就會(huì)造成該崩潰痕慢。
附上簡(jiǎn)單的源碼:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
static NSString *headerID = @"headerID";
ZTGClassSortHeaderView *headerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:headerID];
if (!headerView) {
headerView = [[ZTGClassSortHeaderView alloc] initWithReuseIdentifier:headerID];
}
ZTGResponseGradeListSortEnvelop *gradeEnvelop = [self.sortArray zt_safeObjectAtIndex:section];
ZTGClassSortHeaderItem *haderItem = [[ZTGClassSortHeaderItem alloc] init];
haderItem.gradeString = gradeEnvelop.gradeName;
haderItem.showUp = section == 0 ? NO : YES;
haderItem.showDown = section == self.sortArray.count - 1 ? NO : YES;
haderItem.section = section;
headerView.headerItem = haderItem;
@weakify(self);
haderItem.didSelectedUp = ^(NSInteger indexSection) {
@strongify(self);
NSInteger toSection = indexSection - 1;
if (toSection >= 0 && toSection < self.sortArray.count) {
[self moveSectionFrom:indexSection toSection:toSection];
}
};
haderItem.didSelectedDown = ^(NSInteger indexSection) {
@strongify(self);
NSInteger toSection = indexSection + 1;
if (toSection < self.sortArray.count && toSection >= 0) {
[self moveSectionFrom:indexSection toSection:toSection];
}
};
return headerView;
}
- (void)moveSectionFrom:(NSInteger)section toSection:(NSInteger)toSection {
self.sortChange = YES;
// 更改數(shù)據(jù)
[self.sortArray exchangeObjectAtIndex:section withObjectAtIndex:toSection];
// 移動(dòng)section
[self.sortTableView moveSection:section toSection:toSection];
// 刷新section
ZTGClassSortHeaderView *headerView = (ZTGClassSortHeaderView *)[self.sortTableView headerViewForSection:section];
[self updateSectionStateWithHeader:headerView section:section];
ZTGClassSortHeaderView *toView = (ZTGClassSortHeaderView *)[self.sortTableView headerViewForSection:toSection];
// 此處注釋后會(huì)出現(xiàn)該崩潰,因?yàn)閷?duì)應(yīng)的section沒(méi)有更新
//[self updateSectionStateWithHeader:toView section:toSection];
}
- (void)updateSectionStateWithHeader:(ZTGClassSortHeaderView *)headerView section:(NSInteger)section {
if (headerView.headerItem.updateHeaderState) {
BOOL isUp = section == 0 ? NO : YES;
BOOL isDown = section == self.sortArray.count - 1 ? NO : YES;
headerView.headerItem.updateHeaderState(isUp, isDown, section);
}
}
在headerView.headerItem.updateHeaderState(isUp, isDown, section);
目標(biāo)section不做更新抑堡,再次移動(dòng)時(shí)就會(huì)出現(xiàn)改崩潰催跪。
上面的源碼是tableView section的一部分操作,具體的可以自己寫(xiě)個(gè)簡(jiǎn)單的demo夷野。
解決
針對(duì)以上的崩潰就只能是檢查源碼了懊蒸,一般而言UITableView哪里增、刪section(或row)
就需要對(duì)其進(jìn)行刷新悯搔,如果操作上都是在主線程的話一般而言都是不出會(huì)有問(wèn)題的骑丸,因?yàn)橹骶€程上是串行。而在異步的時(shí)候增妒貌、刪section(或row)
的時(shí)候就需要注意了通危。