[每天记录一个Bug]Cell中由于block加载网络请求产生的复用

Bug 出现场景:
 
cell中使用加载图片的网络请求出现复用,截图如下:
 
 
  EF80175E C0E5 4F8F 8DE5 02087BCB8E68
 
复用原因:
 
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 . chatCreater isEqualToString :user. uid ]) {
    //没被复用
}
else {
    //被复用
}
 
 
代码如下:
 
          IDSLOG ( @"Home msg. model.chatCreater: %@,cell:%@" , model. chatCreater , self );
        @ weakify ( self );
 
        [[ IDSUserCache sharedCache ] findUser :model. chatCreater callback :^( 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 . chatCreater isEqualToString :user. uid ]) {
                NSURL *bgimageUrl = nil ;
                if (! IS_NS_STRING_EMPTY (user. avatar_url )){
                    bgimageUrl = [ AppUtil urlEncodeToNSURL :user. avatar_url ];
                }
               
                static UIImage *defImg;
                static dispatch_once_t onceToken;
                dispatch_once (&onceToken, ^{
                    defImg = [[ IDSImageManager sharedManager ] defaultAvatar : CircleStyle ];
                });
                [ self . avatarImageView sd_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 . nameLabel sizeToFit ];
               
                self . timeLabel . frame = CGRectMake ( CGRectGetMaxX ( self . nameLabel . frame )+ 5 , 0 , 0 , 0 );
                self . timeLabel . text = [ TimeUtil cl_prettyDateWithReference : _chatModel . timestamp ];
                [ self . timeLabel sizeToFit ];
                self . timeLabel . centerY = self . nameLabel . centerY ;
            }
        }];

转载于:https://www.cnblogs.com/firstrate/p/8042486.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
关于 Java 线程池导致 MySQL 的 Bug,可能是由于线程池的线程数量过多,导致 MySQL 连接池被耗尽,从而出现连接超时或者连接泄露的情况。这种情况下,可以通过优化线程池的配置,增加 MySQL 连接池的大小,或者使用连接池管理工具进行监控和管理,来避免这种情况的发生。 至于关于线程池的问题,可以具体分为以下几个方面: 1. 线程池的大小:线程池的大小需要根据实际的业务场景来进行设置,如果线程池的大小过小,可能会导致任务无法及时处理,而过大则会占用过多的系统资源,影响系统的性能表现。 2. 线程池的类型:线程池的类型包括 FixedThreadPool、CachedThreadPool、ScheduledThreadPool 等,不同类型的线程池适用于不同的场景,需要根据实际的业务需求进行选择。 3. 线程池的拒绝策略:当线程池的任务数量超过线程池的最大容量时,需要采取一定的拒绝策略,如 AbortPolicy、CallerRunsPolicy、DiscardOldestPolicy 等,需要根据业务场景和系统性能要求进行选择。 4. 线程池的生命周期管理:线程池的生命周期包括创建、启动、运行、停止等多个阶段,在使用线程池时需要对其进行合理的生命周期管理,以确保线程池的稳定运行和性能表现。 总之,线程池是一个非常重要的并发编程工具,需要在实践不断学习和积累经验,以提高系统的性能和稳定性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值