没错,就是这个老生常谈的复用问题,又一次坑了我(上一次被坑貌似是一年多前了),痛定思痛之后决定记录下,防止以后再犯SB。
先来看看出问题的页面吧:
嗯,就是一个月份的日历,然后每天有不同的任务列表。
实现方式
日历自然是用UICollectionView ,然后UICollectionViewCell里面嵌套了UITableView。
遇到问题
初始化日历的数据是正常的,滑动或者点击刷新后,每日的任务数据就开始各种错,乱显示了。嗯,作为一个稍有经验的程序员,这个时候脑海里当然浮现了两字:复用。
我最开始的思路是这样的:首先外层的日历是正确的,所以应该不是UICollectionCell的问题,而是嵌套在UICollectionViewCell里的的UITableView的UITableViewCell的复用(事实证明这个思路是错误的)。
按照上面的思路我把内部嵌套的UITableView的逻辑梳理了一遍之后,没有发现没问题。
在浪费了一段时间还没解决问题的情况下,我开始审视自己最开始的思路。
每天的任务列表数据是UICollectionCell里面进行传递的:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
ZXCalendarCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
//这里是计算时间的一些操作
NSString *currentTime = [NSString stringWithFormat:@"%@-%@-%@",array[0],array[1],str];
//self.dataArray是一个月的日历数据,遍历找到当天然后把这一天的数据模型scheduleModel给cell,然后cell的tableView会进行显示
for (ScheduleModel *model in self.dataArray) {
if ([model.VisitTime isEqualToString:currentTime]) {
cell.scheduleModel = model;
break;
}
}
//其他一些cell操作
return cell;
}
说真的,看了几遍上述的代码,仍然不觉得有什么问题,逻辑都是通的啊!!!但是,经验告诉我一定是这里出了问题,这里传递数据一定是有问题的!!!
后来脑子终于不秀逗,想明白,于是改成下面的代码:
//先找到当前日期的数据
ScheduleModel *currentModel;
BOOL hasData = NO;
for (ScheduleModel *model in self.dataArray) {
if ([model.VisitTime isEqualToString:currentTime]) {
currentModel = model;
hasData = YES;
break;
}
}
//然后给cell赋值
if (hasData) {
cell.scheduleModel = currentModel;
}else{
cell.scheduleModel = nil;
}
问题解决。
总结
明白的可能一上来就明白了。代码框1里面的那种写法,是有未处理的cell的情况的,因此会出现问题。
简单粗暴地说:所有的cell数据出乱子的问题,不出意外都是cell的复用问题,复用问题不出意外的话都是在cellForItemAtIndexPath:(NSIndexPath *)indexPath 这个方法里写的有问题,而不出意外的话,问题都是没有写全cell的不同情况。比如写了if/else if 而没有else。
题外
明天正式去Node组搬砖干活儿,以后会开个新专题写Node,欢迎继续专注。