ios-UI常见问题之TableView异步加载图片错乱显示

     首先得要知道为什么会出现这个原因   关于uitableview自定义cell与重用机制探究

     比如:1、TableView一次只能显示5行的图片,在所有图片都加载完后,滚动TableView,让隐藏在下面的行显示在屏幕上,而这些行(比如6行)的图像会先显示第1行的图片,然后在显示属于它自己的图片。以此类推,后面的行都会出现这样的问题!! 即使我们在所有行的图片都还没有下载完成的时候,滚动TableView,让第11行、12行等出现在屏幕上,但它们依旧会先显示错误的图片,然后再显示正确的图片。


    iphone重用机制是苹果为了实现大量数据显示而采用的一种节省内存的机制,比如在UITableView和ScrollView 等地方。为什么要“可重用”???对于我们的项目来说,内存控制是必不可少的,如果一个tableview有几百个cell,这个内存消耗是很大的,而且有些cell里面都有image之类的很占内存的资源存在的话,那这样很容易出现memory warning甚至crash掉,这不是我们想要看到的。对此,tableview实现了它自己的管理方法dequeueReusableCellWithIdentifier(ps:我们在某些项目中scrollview来显示很多张image,在scrollview滑动中也要这样处理,来避免内存的过度消耗,只不过tableview它已经实现了这个方法,而不用我们自己去写)。


但是在实际使用过程中,会有以下问题:

1、(苹果文档中不鼓励我们在UITableViewCell中添加subView,最好采用自定义Cell,将需要的SubView添加到Cell当中。)使用addSubView在每项上添加视图的时候会有重叠的现象。例如,UITableView中的Cell ,如果在cell上添加子视图,则在使用苹果的重用机制的时候,会重现子试图重叠的现象。或出现开头提到的两个问题。如果在数据量不是很多的时候,可以手动屏蔽掉UITableView的重用机制。

这里不得不提一下UITableView的重用机制:

UITableView的重用机制的实现关键在于下面这个的函数:

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

首先,我们要清楚这一点,这个函数是做什么的,它的文档说明如下:
returns a reusable table-view cell object located by its identifier。它返回的是一个受identifier管理定位的可重用的tableViewCell,这里重点就在于“可重用”这3个字上。

我们来看它的实现方法,举个例子来说,在系统刚启动时,tableview可以显示多少个cell,在这里我们假定为10个,在刚开始的时候tableview会生成10个tableviewcell,并且对应有自己的tag值,假定为0-9。(ps:苹果官方的视频中也提到了,尽量避免频繁的add/remove view或者控件之类等。自定义啊自定义,相对于Android 空间的自定义,)所以采用下面的方法来实现:在tableview向上滚动的时候,tag为0的cell将不再显示;然后我们把tag为0的cell移动到tag为9的cell下面,重新设置相关的属性,然后将tag为1的cell移动到tag为0的cell下面……依此类推。这也就是所谓的“可重用”。

CellIdentifier 组别,行数不一样) 只要咱们干掉重用机制就可以很好的解决这个问题(组别,行数不一样)

NSString *CellIdentifier = [NSString stringWithFormat:@"cell%d",indexPath.row];
    
           UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
          if (cell == nil) 

                {
                               ........
                 }
         else{
                        return cell;
               }       

给 ImageView 设置一个 tag, 并预设一个图片。

当 Item1 比 Item8 图片下载的快时, 你滚下去使 Item8 可见,这时 ImageView 的 tag 被设成了

Item8 的 URL, 当 Item1 下载完时,由于 Item1 不可见现在的 tag 是 Item8 的 URL,所以不满足条件,

虽然下载下来了但不会设置到 ImageView 上, tag 标识的永远是可见 view 中图片的 URL。

这只是一个片面的方法  更稳健的办法是为要先显示的imageView 设置一个tag值,tag值等于imageUrl值 这样就能很好的解决问题

我再简单分析一下:

当重用 convertView 时,最初一屏显示 7 条记录, getView 被调用 7 次,创建了 7 个 convertView.

当 Item1 划出屏幕, Item8 进入屏幕时,这时没有为 Item8 创建新的 view 实例, Item8 复用的是

Item1 的 view 如果没有异步不会有任何问题,虽然 Item8 和 Item1 指向的是同一个 view,但滑到

Item8 时刷上了 Item8 的数据,这时 Item1 的数据和 Item8 是一样的,因为它们指向的是同一块内存,

但 Item1 已滚出了屏幕你看不见。当 Item1 再次可见时这块 view 又涮上了 Item1 的数据。

 

但当有异步下载时就有问题了,假设 Item1 的图片下载的比较慢,Item8 的图片下载的比较快,你滚上去

使 Item8 可见,这时 Item8 先显示它自己下载的图片没错,但等到 Item1 的图片也下载完时你发现

Item8 的图片也变成了 Item1 的图片,因为它们复用的是同一个 view。 如果 Item1 的图片下载的比

Item8 的图片快, Item1 先刷上自己下载的图片,这时你滑下去,Item8 的图片还没下载完, Item8

会先显示 Item1 的图片,因为它们是同一快内存,当 Item8 自己的图片下载完后 Item8 的图片又刷成

了自己的,你再滑上去使 Item1 可见, Item1 的图片也会和 Item8 的图片是一样的,

因为它们指向的是同一块内存。

最后给大家推荐一个第三方库 SDWebImage-ProgressView

使用这个就能很好的解决上诉问题了



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值