Bug 出现场景:
cell中使用加载图片的网络请求出现复用,截图如下:
复用原因:
Cell Model中只有一个用户的uid,所有用户相关信息:例如头像\名称\信息等是通过 block请求,通过uid 回调中取到的字段,但由于是在cell中通过系统的block回调中下载得到的头像,所以会有延时问题.
当使用 self.collection reloadData ,这个语句的时候,由于4个cell的头像还没加载成功,瞬间又重新复用4个cell出来,就会产生复用的情况。
也就是说 4个cell地址如下:
0XA1
0XA2
0XA3
0XA4
4个cell地址正序排列,分别取block请求拉取头像的时候,此时还没有拉取成功,瞬间执行语句 self.collection reloadData。cell 会产生复用机制,地址排列顺序如下:
0XA4
0XA3
0XA2
0XA1
此时就会产生复用,由于第一个cell网络请求较快,但是第4个cell请求比较慢,就会产生复用:
因为
0XA1 头像加载成功
0XA2
0XA3
0XA4 头像未加载成功
reloadData后复用
0XA4 头像加载成功,但是由于复用之前block还没有加载成功,导致在之前cell中的0XA4的头像直接覆盖了,复用后的0XA4的头像。
0XA3
0XA2
0XA1 由于复用钱0XA1头像加载速度较快,所以这个cell不会出现复用情况。适合网络加载快慢相关
cell中使用block进行网络请求,就容易出现此问题。
即时在 cell中的 prepareReuse()方法中将cell置nil,也会出现复用问题,因为根本原因是在block块中出现的复用问题。
解决方案:
在 block 块中 ,记录回调前的 user.uid 数据,然后和 cell此时记录的变量 model.uid 进行对比,因为model.uid是cell自带的字段,不会被复用的字段,而block中的user.uid是block回调后的字段,可能是之前cell中保留的字段。
进行对比,就知道block是复用前的,还是复用后的。
block里的变量不会变,但是复用后的cell Model会变。
解决方案 :
user.uid block回调产生的用户字段,_chatModel.chatCreater 是Model中的字段,不会被block所截取的临时变量。
if ([_chatModel.chatCreaterisEqualToString:user.uid]) {
//没被复用
}
else {
//被复用
}
代码如下:
IDSLOG(@"Home msg. model.chatCreater: %@,cell:%@", model.chatCreater,self);
@weakify(self);
[[IDSUserCachesharedCache] findUser:model.chatCreatercallback:^(NSArray<IDSLoginUser *> *users) {
@strongify(self);
if (IS_NS_COLLECTION_EMPTY(users)) {
return;
}
IDSLoginUser *user = [users cl_objectAtIndex:0];
IDSLOG(@"_chatModel.chatCreater : %@, user.uid:%@, model.chatCreater:%@", _chatModel.chatCreater, user.uid, model.chatCreater);
if ([_chatModel.chatCreaterisEqualToString:user.uid]) {
NSURL *bgimageUrl = nil;
if (!IS_NS_STRING_EMPTY(user.avatar_url)){
bgimageUrl = [AppUtilurlEncodeToNSURL:user.avatar_url];
}
staticUIImage *defImg;
staticdispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
defImg = [[IDSImageManagersharedManager] defaultAvatar:CircleStyle];
});
[self.avatarImageViewsd_setImageWithURL:bgimageUrl
placeholderImage:defImg
options:SDWebImageRetryFailed|SDWebImageLowPriority];
self.nameLabel.text = user.username;
self.nameLabel.frame = CGRectMake(CGRectGetMaxX(self.avatarImageView.frame)+7,
CGRectGetMinY(self.chatLabel.frame)-7-self.nameLabel.contentSize.height, 0, 0);
self.avatarImageView.layer.cornerRadius = self.avatarImageView.frame.size.width/2.0;
[self.nameLabelsizeToFit];
self.timeLabel.frame = CGRectMake(CGRectGetMaxX(self.nameLabel.frame)+5, 0, 0, 0);
self.timeLabel.text = [TimeUtilcl_prettyDateWithReference:_chatModel.timestamp];
[self.timeLabelsizeToFit];
self.timeLabel.centerY = self.nameLabel.centerY;
}
}];