1.要解决的问题.缓存
给单元格设置从网络上下载的图片.网络
2.思路:异步
>1.先同步下载布局
bug:下载是一个耗时操做,会阻塞主线程优化
>2.异步下载图片atom
bug:图片发生错行.url
>从网络上请求下来的图片与单元格不匹配.为何会这样?根本缘由是由于重用单元格.spa
如图所示.线程
tableView上有3个单元格.每一个单元格有图片,文字.文字是经过plist加载,当向上滚动单元格,让,单元格1滚出界面,那么就会加载第4个单元格,第四个单元格仍然是新建立的,由于当单元格1还没有滚出视图,单元格4已经出来一部分,是不可能重用的.当单元格4彻底加载出来,单元格1彻底滚出界面,缓存池中就有了可重用单元格,当加载第5个单元格,就不会重写建立单元格,而是到缓存池中找,因而把第1个单元格,放到第5个单元格的位置,若是此时并不根据indexPath设置第五个单元格的数据,那么就会发生单元格重用,第5个单元格和第1个单元格彻底同样,所以,一般为了解决单元格重用,须要根据indexPath从新设置单元格5的数据.code
由于从网络上请求数据是比较耗时的,可能会发生这样一种状况:
单元格1的图片还没有请求到,就已经滚出界面,单元格5重用了单元格1的数据,经过根据indexPath获取plist文件中对应的文字数据,能够方式重用致使的问题.单元格一样要发送请求到网络上请求本身的图片,可是若是单元格1请求图片比较慢,那么,单元格5会先设置本身的图片,而后又设置单元格1的图片,因而发生覆盖.致使图片与文字不匹配.
那么plist设置文字会发生这种情况么?首先,我以为若是从plist文件中加载数据也像从网络中请求数据那样耗时,而且取不一样的字符串耗时差距比较大,也会发生覆盖问题.可是我以为从本地取数据是很快的,而且,便是耗时,从plist中取一个长度为10,和长度为100的字符串也是差很少的.这种偏差一般应该不会发生
SDWebImage的解决方式,便是斩断这种多个数据填一单元格的问题,当单元格已经出去了,却没有下载好图片,那么就取消单元格1的下载操做,因而滚到单元格5的时候,这个单元格就只有一个网络请求,不会再有比它更慢的网络请求的图片回来覆盖单元格5对应的正确的数据.
这种实现比较麻烦,先考虑简单的解决方式.
方式1:并不直接将网络请求的数据设置给单元格,而是经过给plist文件对应的模型增长一个属性UIImage,由于模型数据老是一一对应的,由于角标不一样,当单元格1的图片数据请求回来,设置给模型中的image属性,由于---------会不会发生这种状况,将请求回来的图片设置给模型的image属性的时候发生错乱?好比,单元格1请求数据比较慢,单元格3请求下来的数据设置给单元格1对应的image属性?就目前这种写法,应该不会,由于实际上,每次请求图片都是新开了了线程,若是CPU分配,那么每个单元格对应着一个线程,也就是单元格3请求数据和单元格1请求图片和设置图片是在不一样线程,不会发生设想的问题.假设CPU并不让每个单元格从新开线程,而是上一个执行完了再将新的任务添加到同一个线程中,也不会发生设想的这种错乱.
由于设置数据的时候,是在子线程请求图片的,于是能够直接忽略该段代码,于是会致使一个bug,图片请求回来了,却并无图片,由于控件是懒加载,当第一次布局单元格的时候,并无图片请求回来,于是layoutSubViews不会布局图片框的位置,当滑动或者点击单元格,又会调用layoutSubViews方法,此时系统意识到有图片,于是会布局图片,该问题能够经过占位图解决,
方式2:
思路和前面仍然是同样,不直接将下载的数据和单元格关联,经过一个中介将下载的图片和plist文件一一对应便可.字典是一一对应的,将模型中的url做为键,(每一个单元格都不一样,于是是惟一的),将图片做为值存储起来.此时还须要在下载图片前先从图片缓存字典中取,若是有,就设置图片,没有就下载,也能够解决错行问题.SDWebImage只不过是经过NSCache解决的,实现思路也是同样.而且NSCache其实和字典也差很少,只须要setObjectForKey存,ObjectForKey取便可.
>3.有网状态下下载下来的图片须要缓存到本地,这样,当没网,就能够到缓存中取.数据本地化可使用归档或者plist,我用的是plist,注意,当没有网的时候就能够从沙盒中找.又因为,从沙盒中取效率不如从内存中取高,当第一次从沙盒中加载,再次上下滑动时候,考虑从内存中去,因而能够从沙盒中取出图片后,同时将图片设置给图片缓存.又若是是第一次从网上加载,再次上下滑动,从沙盒中加载,不如直接从内存中加载效率高,考虑从网上下载后一样设置给图片缓存(内存).
>4.bug3,即便图片下载下来了,可是再次滚动单元格仍是会再去下载,这显示是不必的,我最初的想法是,给模型增长一个BOOL值,当任务被添加到队列中,将BOOL值设置为YES,表示正在下载,没必要重复下载,实际上也是能够解决问题的.可是又有一个问题.若是用户清除缓存了,而且程序没有挂掉,也就是说沙盒中,没有图片,那么能够去图片缓存中取,若是从新运行程序,BOOL值又恢复为nil,又从网上加载,貌似没有问题.????为啥还要移除操做缓存????有没有这样一种可能,BOOL值显示为正在下载,可是图片缓存中没有数据,沙盒中也没有数据,可是又由于BOOL值显示正在下载致使没法再次下载???有可能,当收到内存警告,内存中被清空了,沙盒中又被清除缓存,模型中的BOOL值仍然显示着正在下载,致使没法再次下载.-----确实有问题,当收到内存警告,内存缓存中的图片缓存会被清空,而且沙盒中也被清除缓存,此时操做缓存中显示正在下载,不会再次下载,若是设置了占位图,就会发生只有占位图,若是没有设置占位图,就会发生图片复用.于是,当图片下载完成,须要将操做缓存移除.
>5.经过BOOL值确实能够解决重复下载的问题,可是呢,这样会不会形成代码的耦合性太高呢?假设须要将下载之外的事务抽取出来,不放在控制器中,专门封装到一个管理者类中,操做缓存这一步该如何封装进去?-----若是经过增长BOOL值记录操做缓存,那么须要用到模型,然而,管理者类中又用到模型,耦合性实在过高,故而此种作法很差.
>6.在增长新的东西前,先优化一下当前代码,你不以为设置单元格的方法太过于冗长了么?怎么抽取一下?...不管是抽取到自定义单元格中仍是抽取到一个单独的方法,须要的参数都不少,暂时不这样作.
>7.增长一个管理者类,将下载无关的业务逻辑抽取出来,须要在三个类之间进行传值,能够经过block解决.而且比较容易实现.须要注意一个问题
管理者类中用到了block,
typedef void(^giveImageToVc)(UIImage * image);
属性
@property (nonatomic,copy) giveImageToVc giveImageToVc;
// 须要回到主线程操做. if (self.giveImageToVc) { self.giveImageToVc(img);//此处省略self,并不会报错,由于,默认的识别为起别名的block, } return ;
像这样:
typedef void(^myblock)(UIImage *); - (void)test:(NSString *)urlString { myblock(abc);//而且括号中的参数写什么都不会报错
>8.由于要仿SDWebImage,SDWebImage解决图片错行的方式和上面的方式稍稍不一样,其思路是这样的:
由于根本缘由在于多个请求填一个单元格,那么当滚到新的单元格的时候,若是还有旧的单元格请求绑定着新的单元格,那么只须要切断就的请求便可.而且SDWebImage是经过给UIImageView添加分类的方式,于是我也这样作,那么在分类方法中就要作这几件事:
仍然以上面的示例图片为例,假设单元格1已经滚出屏幕,单元格4滚入屏幕,那么单元格4滚进屏幕,须要作这样的判断,判断单元格1的图片是否下载完成,若是已经完成,由于当下载完成了,就会执行设置图片操做,由于覆盖问题就是一方面是由于重用,一方面也是由于请求图片比较耗时,若是单元格1已经下载完成,那么单元格4下载图片确定在其后,不会发生覆盖.若是单元格1还没有下载完成,那么就有可能比单元格4下载慢,致使覆盖
于是,若是知足当滚动到单元格4的时候,单元格1还没有下载完成,那么就取消单元格1的下载操做,执行单元格1的下载操做.
?问题1;如何断定单元格1是否下载完成?
?问题2:由于要在分类中记录单元格1的urlString,一般是经过属性记录,然而,分类是不能增长属性的.可不能够用静态全局变量
?问题3:第一次进来,oldURLString 为nil,将当前urlString赋值给oldURLString,第二次进来,存储的是就是第一个单元格的urlString,界面上能显示3个单元格,显然此时单元格1和单元格2,3不会发生覆盖问题,当加载第四个单元格的时候,须要判断的是第一个单元格是否下载完成,那么如何判断当前滚动出来的单元格是界面中最底下的呢?
或者说加载第二个单元格时,第一个还没有加载完,取消,这样到加载第四个单元格的时候也不会发生多个数据抢一个单元格的问题.可是这样太狠了,有一些操做是不必的,损耗效率的.思路有问题.....
由于加载每一个单元格都会调用分类方法,也就是说,只有当第一个单元格成为第4个单元格的时候才可能发生覆盖问题,才须要判断第一个单元格是否下载完成,那么首先要判断当前传进来的URL是不是第四个,这样有问题,若是屏幕显示的图片不止四个呢?屏幕显示多少个单元格取决于单元格高度和手机屏幕,这些都是不可控制的.思路有问题.....
果真有问题
问题大大的