首页 > 代码库 > iOS开发项目篇—46时间和来源的处理(cell的复用问题)

iOS开发项目篇—46时间和来源的处理(cell的复用问题)

iOS开发项目篇—46时间和来源的处理(cell的复用问题)
一、简单说明

1.存在的问题:

           

2.问题描述:

刷新微博界面后,展示的最新的微博数据时间显示为“刚刚”,在项目中对时间进行设计的时候,如果是在1分钟之内发表的,那么显示为“刚刚”。查看后面的微博数据后,回过头来(1分钟已经过去了),此时之前显示为“刚刚”的微博,应该显示XX分钟以前,确实显示了,但是时间的frame不正确(此时的frame=="刚刚"两个字的frame)。

提示:cell的复用问题,为了提升性能节省内存,cell在设计的时候是只创建显示到眼前【界面】上的cell,当滚动的时候,复用之前创建的cell。

3.问题出在了哪里?

根据展示的效果,时间从“刚刚”--》“XX分钟之前”,可以知道代码设计部分已经完成了实时对“时间”数据进行更新的功能(总是拿微博发表的时间和当前的时间进行比较,再显示提示的时间信息),但是frame却没有被再次计算,还是之前的数值,也就是说在整个过程中,时间的显示【“刚刚”  “XX分钟前” “一小时前”】等是不断刷新计算的,而显示时间的frame在程序中只被设置了一个初值,之后并没有同步的进行设置。

4.简单说明:显示时间的label的宽度永远是“刚刚”这两个汉字的宽度。

 

二、解决cell的复用产生的问题

显示时间的label的frame不能只计算一次,也应该要实时的进行更新。

1.在原创微博frame中再计算时间和来源的frame没有意义,删除相关代码。

提示:因为微博来源的frame和时间label的frame有直接的关系,所以连带着也应该计算来源的frame。

YYStatusOriginalFrame.h文件

 1 // 2 //  YYStatusOriginalFrame.h 3 // 4  5 #import <Foundation/Foundation.h> 6  7 @class YYStatusModel; 8 @interface YYStatusOriginalFrame : NSObject 9 /**10  *  微博数据模型11  */12 @property(nonatomic,strong)YYStatusModel *status;13 14 /** 昵称 */15 @property (nonatomic, assign) CGRect nameFrame;16 /** 正文 */17 @property (nonatomic, assign) CGRect textFrame;18 ///** 来源 */19 //@property (nonatomic, assign) CGRect sourceFrame;20 ///** 时间 */21 //@property (nonatomic, assign) CGRect timeFrame;22 /** 头像 */23 @property (nonatomic, assign) CGRect iconFrame;24 /** 会员图标 */25 @property (nonatomic, assign) CGRect vipViewFrame;26 27 /** 自己的frame */28 @property (nonatomic, assign) CGRect frame;29 @end

2.需要时刻根据现在的时间计算,显示时间和微博来源的label的frame

YYStatusOriginal.m文件

  1 //  2 //  YYStatusOriginal.m  3 //  4   5 #import "YYStatusOriginalView.h"  6 #import "YYStatusOriginalFrame.h"  7 #import "YYUserModel.h"  8 #include "YYStatusModel.h"  9 #import "UIImageView+WebCache.h" 10  11 @interface YYStatusOriginalView () 12 /** 13  *  头像 14  */ 15 @property(nonatomic,weak)UIImageView *iconView; 16 /** 17  *  昵称 18  */ 19 @property(nonatomic,weak)UILabel  *nameLabel; 20 /** 21  *  微博的正文 22  */ 23 @property(nonatomic,weak)UILabel *textLabel; 24 /** 25  *  时间 26  */ 27 @property(nonatomic,weak)UILabel *timeLabel; 28 /** 29  *  来源 30  */ 31 @property(nonatomic,weak)UILabel *sourceLabel; 32 /** 33  *  会员图标 34  */ 35 @property(nonatomic,weak)UIImageView *vipView; 36  37 @end 38 @implementation YYStatusOriginalView 39  40 - (id)initWithFrame:(CGRect)frame 41 { 42     self = [super initWithFrame:frame]; 43     if (self) { 44         //初始化子控件 45         //1.头像 46         UIImageView *iconView=[[UIImageView alloc]init]; 47         [self addSubview:iconView]; 48         self.iconView=iconView; 49          50         //2.昵称 51         UILabel *nameLabel=[[UILabel alloc]init]; 52         nameLabel.font=YYStatusOrginalNameFont; 53         [self addSubview:nameLabel]; 54         self.nameLabel=nameLabel; 55          56         //3.正文 57         UILabel *textLabel=[[UILabel alloc]init]; 58         textLabel.font=YYStatusOrginalTextFont; 59         textLabel.numberOfLines=0; 60         [self addSubview:textLabel]; 61         self.textLabel=textLabel; 62          63         //4.时间 64         UILabel *timeLabel=[[UILabel alloc]init]; 65         timeLabel.font=YYStatusOrginalTimeFont; 66         timeLabel.textColor=[UIColor orangeColor]; 67         [self addSubview:timeLabel]; 68         self.timeLabel=timeLabel; 69          70         //5.来源 71         UILabel *sourceLabel=[[UILabel alloc]init]; 72         sourceLabel.font=YYStatusOrginalSourceFont; 73         sourceLabel.textColor=[UIColor lightGrayColor]; 74         [self addSubview:sourceLabel]; 75         self.sourceLabel=sourceLabel; 76          77         //6.会员图标 78         UIImageView *vipView=[[UIImageView alloc]init]; 79         //会员图标应该设置保持原来的尺寸,垂直居中 80         vipView.contentMode=UIViewContentModeCenter; 81         [self addSubview:vipView]; 82         self.vipView=vipView; 83          84     } 85     return self; 86 } 87  88 -(void)setOriginalFrame:(YYStatusOriginalFrame *)originalFrame 89 { 90     _originalFrame=originalFrame; 91      92     //设置自己的frame 93     self.frame=originalFrame.frame; 94      95     //取出模型数据 96     YYStatusModel *status=originalFrame.status; 97      98     //设置头像的frame 99     [self.iconView setImageWithURL:[NSURL URLWithString:status.user.profile_image_url] placeholderImage:[UIImage imageWithName:@"avatar_default_small"]];100     self.iconView.frame=originalFrame.iconFrame;101     102     //设置昵称的frame103     self.nameLabel.text=status.user.name;104     //注意循环利用的问题105     if (status.user.isVip) {106         self.nameLabel.textColor=[UIColor orangeColor];107         self.vipView.hidden=NO;108         self.vipView.frame=originalFrame.vipViewFrame;109         self.vipView.image=[UIImage imageWithName:[NSString stringWithFormat:@"common_icon_membership_level%d",status.user.mbrank]];110     }else111     {112         self.nameLabel.textColor=[UIColor blackColor];113         self.vipView.hidden=YES;114     }115     self.nameLabel.frame=originalFrame.nameFrame;116     117     //设置正文的frame118     self.textLabel.text=status.text;119     self.textLabel.frame=originalFrame.textFrame;120   121 #warning 需要时刻根据现在的时间计算,显示时间和微博来源的label的frame122     //设置时间的frame123     NSString *timeStr=status.created_at;124     self.timeLabel.text=timeStr;125     126     CGFloat timeX=CGRectGetMinX(self.nameLabel.frame);127     CGFloat timeY=CGRectGetMaxY(self.nameLabel.frame)+YYCellStatusInset*0.5;128     CGSize timeSize=[timeStr sizeWithFont:YYStatusOrginalTimeFont];129     self.timeLabel.frame=(CGRect){{timeX,timeY},timeSize};130     131     //设置来源的frame132     self.sourceLabel.text=status.source;133     134     CGFloat sourcceX=CGRectGetMaxX( self.timeLabel.frame)+YYCellStatusInset;135     CGFloat sourcceY=timeY;136     CGSize sourcceSize=[status.source sizeWithFont:YYStatusOrginalSourceFont];137     self.sourceLabel.frame=(CGRect){{sourcceX,sourcceY},sourcceSize};138     139 }140 @end

 

3.修复了这个问题的显示效果:

     

4.性能优化处理

  说明:

(1)每次刷新,都需要对时间进行处理,但是微博的来源是固定的,没必要每次刷新的时候就调用一次浪费掉宝贵的内存空间。

(2)且在设置微博来源的时候,是通过截取并拼接字符串这样的方式进行的,而这恰是特别耗时的操作。没必要每次调用self.sourceLabel.text=status.source;的时候都去拼接字符串(这个方法调用非常频繁,每当一个cell进入到视野的时候,都会计算一遍)。

(3)计算时间,每次得出的结果是不一样的。但是计算微博来源,每次截取字符串都是固定的,是一样的。

(4)set方法只会在字典转模型的那一刻调用(因为要把字典属性赋值给模型属性),get方法时刻都在调用。

(5)解决方法:删除get方法,重写一个相应的set方法

YYStatusModel.m文件

  1 //  2 //  YYStatusModel.m  3 //  4   5 #import "YYStatusModel.h"  6 #import "MJExtension.h"  7 #import "YYPhotoModel.h"  8 #import "NSDate+MJ.h"  9  10 @implementation YYStatusModel 11 //+(instancetype)statusModelWithDict:(NSDictionary *)Dict 12 //{ 13 //    YYStatusModel *model=[[self alloc]init]; 14 //    model.text=Dict[@"text"]; 15 //     16 //    model.user=[YYUserModel userModelWithDict:Dict[@"user"]]; 17 //     18 //    //嵌套模型 19 //    NSDictionary *retweetedDict = Dict[@"retweetedDict"]; 20 //    if (retweetedDict) { 21 //        model.retweeted_status=[YYStatusModel statusModelWithDict:retweetedDict]; 22 //    } 23 //    return model; 24 //} 25  26 -(NSDictionary *)objectClassInArray 27 { 28       return @{@"pic_urls" : [YYPhotoModel class]}; 29 } 30  31 //重写创建时间的get方法 32 /**_created_at==Sat Jul 19 15:24:04 +0800 2014*/ 33 -(NSString *)created_at 34 { 35 //    _created_at=@"Sat Jul 18 15:24:04 +0800 2014"; 36     NSDateFormatter *fmt=[[NSDateFormatter alloc]init]; 37     //时间格式 38     fmt.dateFormat = @"EEE MMM dd HH:mm:ss Z yyyy"; 39     //获得尾部发布的具体时间 40     NSDate *creatDate = [fmt dateFromString:_created_at]; 41      42     //判断是否为今年 43     if (creatDate.isThisYear) {//今年 44         if (creatDate.isToday) { 45             //获得微博发布的时间与当前时间的差距 46             NSDateComponents *cmps=[creatDate deltaWithNow]; 47             if (cmps.hour>=1) {//至少是一个小时之前发布的 48                 return [NSString stringWithFormat:@"%d小时前",cmps.hour]; 49             }else if(cmps.minute>=1){//1~59分钟之前发布的 50                 return [NSString stringWithFormat:@"%d分钟前",cmps.minute]; 51             }else{//1分钟内发布的 52                 return @"刚刚"; 53             } 54         }else if(creatDate.isYesterday){//昨天发的 55             fmt.dateFormat=@"昨天 HH:mm"; 56             return [fmt stringFromDate:creatDate]; 57         }else{//至少是前天发布的 58             fmt.dateFormat=@"MM-dd HH:mm"; 59             return [fmt stringFromDate:creatDate]; 60         } 61     }else           //  往年 62     { 63         fmt.dateFormat=@"yyyy-MM-dd"; 64         return [fmt stringFromDate:creatDate]; 65     } 66 } 67 /**_source== <a href="http://www.mamicode.com/http://app.weibo.com/t/feed/3j6BDx" rel="nofollow">孔明社交管理</a>*/ 68 //所需要的:孔明社交管理 69 //-(NSString *)source 70 //{ 71 //    //截取字符串,获得子串 72 //    //截取的范围 73 //    NSRange range; 74 //    //截取的位置:第一个>之后 75 //    range.location=[_source rangeOfString:@">"].location+1; 76 //    //截取的长度:第二个<的位置到第一个>之间的长度 77 //    range.length=[_source rangeOfString:@"</"].location-range.location; 78 //     79 //    //开始截取 80 //    NSString *subSource=[_source substringWithRange:range]; 81 //    //头部拼接“来自” 82 //    return [NSString stringWithFormat:@"来自%@",subSource]; 83 //} 84  85 -(void)setSource:(NSString *)source 86 { 87     //截取字符串,获得子串 88     //截取的范围 89     NSRange range; 90     //截取的位置:第一个>之后 91     range.location=[source rangeOfString:@">"].location+1; 92     //截取的长度:第二个<的位置到第一个>之间的长度 93     range.length=[source rangeOfString:@"</"].location-range.location; 94  95     //开始截取 96     NSString *subSource=[source substringWithRange:range]; 97     //头部拼接“来自” 98     _source = [NSString stringWithFormat:@"来自%@",subSource]; 99 }100 101 @end

提示:KVC的本质也是调用set方法。