reloadRowsAtIndexPaths 一般用于刷新一組 cell秀睛,筆者在使用過程中發(fā)現(xiàn)慨仿,調(diào)用該方法后 Tableview 并不是刷新 cell,而是會重新創(chuàng)建 cell钾唬。
并且 cell 的重用會發(fā)生錯亂十办,在 IndexPath [0, 0] 下創(chuàng)建的 cell 會在 IndexPath [0, 1] 下被重用仓犬。
比如一個常見的需求,在 TableView 第一行顯示頭像舍肠,第二行顯示昵稱搀继。假設這兩條信息是單獨從服務器獲取的。
模擬網(wǎng)絡請求代碼如下:
- (void)viewDidLoad {
[super viewDidLoad];
_titles = @[@"Avator", @"Nickname"];
[self.tableView registerClass:[SFTableViewCell class] forCellReuseIdentifier:kCellIdentifier];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(kDelayTime * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
_avator = [UIImage imageNamed:@"cat"];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(kDelayTime * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
_nickName = @"Smallfly";
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:1 inSection:0];
[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
});
});
}
但實際的的顯示結(jié)果卻是這樣:
再來看一下 TableView DataSource 的實現(xiàn):
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// Why reloadRowsAtIndexPaths [0,0] returned cell is nil?
SFTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellIdentifier forIndexPath:indexPath];
cell.textLabel.text = _titles[indexPath.row];
if (indexPath.row == 0) {
[self configureCell:cell indexPath:indexPath];
} else {
NSString *nickName = _nickName ?: @"nickname";
cell.detailTextLabel.text = nickName;
}
return cell;
}
在 indexPath.row == 0 的時候為 cell 添加頭像:
- (void)configureCell:(UITableViewCell *)cell indexPath:(NSIndexPath *)indexPath {
for (UIView *sv in cell.contentView.subviews) {
if ([sv isKindOfClass:[UIImageView class]]) {
[sv removeFromSuperview];
}
}
UIImage *avator = _avator ?: [UIImage imageNamed:@"user_profile_avatar"];
UIImageView *avatorImageView = [[UIImageView alloc] initWithImage:avator];
// configure imageView...
[cell.contentView addSubview:avatorImageView];
}
為防止重復的添加 imageView 翠语,先將存在的頭像移除叽躯。
進行一番調(diào)試之后筆者發(fā)現(xiàn),在請求前肌括,兩個 cell 的地址為:
<SFTableViewCell: 0x7fb1bf826c00> // indexPath [0, 0]
<SFTableViewCell: 0x7fb1be00fc00> // indexPath [0, 1]
在請求后調(diào)用 reloadRowsAtIndexPaths 兩個 cell 的地址為:
<SFTableViewCell: 0x7fb1be001600> // indexPath [0, 0]
<SFTableViewCell: 0x7fb1bf826c00> // indexPath [0, 1]
存在詭異的地方:
- 在 reloadRowsAtIndexPaths 是 indexPath [0, 0] 的 cell 被重新創(chuàng)建了点骑。
- indexPath [0, 1] cell 地址等于 indexPath [0, 0] cell 的地址。
因為以上兩個問題谍夭,導致在刷新第二行 cell 時出現(xiàn)了原本在第一行的默認頭像黑滴,如果用 reload 刷新整個 TableView 則不會有這樣的問題。
當然紧索,最好的方式是自定義頭像 cell袁辈,為方便起見使用這種方式,發(fā)現(xiàn)了這個問題珠漂。如果有大神知道原理晚缩,請指點一二 。
參考 Demo 地址 UITableViewBug