ios - UITableView中大图片加载时卡顿问题
伊谢尔伦
伊谢尔伦 2017-04-17 11:07:42
[iOS讨论组]

我的UITableView中有若干UIButton,图片存放于本地硬盘,读取到内存后放进UIButton展示。

子线程负责从文件读入图片到内存,主线程用setImage:forState:展示。由于setImage:forState:耗时较长且在主线程,导致Table拖动起来较卡。代码如下(UIButton上的扩展):

- (void)asyncLoadImageAtPath:(NSString *)fullPath forState:(UIControlState)state
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        UIImage *image = [[UIImage alloc] initWithContentsOfFile:fullPath];
        dispatch_async(dispatch_get_main_queue(), ^{
            [self setImage:image forState:state];
        });
    });
}

后将setImage:forState:移入子线程,卡是不卡了,但是setImage:forState线程不安全,setImage:forState调用两秒后才会被显示。代码改为:

- (void)asyncLoadImageAtPath:(NSString *)fullPath forState:(UIControlState)state
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        UIImage *image = [[UIImage alloc] initWithContentsOfFile:fullPath];
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
            [self setImage:image forState:state];
        });
    });
}

QQ电影票中存于本地的大图拖起来不卡,且看起来是线程安全的。不知是怎么做的?

解决:最后读图重画成小尺寸一个线程,渲染一个线程,性能和自带的Photos差不多

伊谢尔伦
伊谢尔伦

小伙看你根骨奇佳,潜力无限,来学PHP伐。

全部回复(3)
PHPz

先在其他线程做async loading,就是其中的initWithContentsOfFile,然后当image loading完了再调用主线程update UI.

dispatch_queue_t imagequeue = dispatch_queue_create("com.company.imageLoadingQueue", NULL);
    
    // Start the background queue
    dispatch_async(imagequeue, ^{
      UIImage *image = [[UIImage alloc] initWithContentsOfFile:fullPath];
      dispatch_async(dispatch_get_main_queue(),
           ^{
               [self setImage:image forState:state];
            }); //end of main thread queue
    }); //end of imagequeue

    dispatch_release(imagequeue);
高洛峰

把图片等比例缩小。网络加载大图片必然要卡,SDWebImage这个开源项目也是去缩小图片的。

怪我咯

我觉得,你这个问题不处在UIButton的渲染上。根据我的经验,这种情况造成的卡,有两个点要去优化:

  1. 单独控件(一个UIButton)内的对象数量。这方面你不存在问题,一个Cell一个UIButton,一个UIButton一个UIImage
  2. 单独UIImage对象内的图片大小。我遇到的问题是在iPad1或2上使用了兼容iPad3而采用的高分图片造成的卡

我想这两个问题你都不存在,那么问题就处在你的图片载入顺序不合理。看你的描述不知道你是UITableView还是用UIScrollView实现的瀑布流,如果是UITableView,就没必要用Button了,因为每个Cell都是可点击的。如果是UIScrollView实现的瀑布流,优化余地较大。这里假设你是瀑布流的图片

  1. 降低刷新频率。通过UIScrollView的代理方法,没滚动超过100或200像素,才检测一次可视区域,刷新控件。
  2. 适时地回收控件。我们认为用户单方向滑动ScrollView的时候是一种趋势,也就是说当向下滑动到某一位置,那么意味着他即将继续向下滑动。因此一般建议向用户滑动方向一屏幕高度,反向半屏幕高度,加当前屏幕高度,供2.5屏幕高度的位置是活跃区域,活跃区域意外的控件,你这里就是一个UIButton,回收,放进一个池,等待复用。
  3. 复用回收的空间。当非活跃区域进入状态,从池内提取控件,载入数据,进行显示。这样可以保证不论用户如何操作,总能保证整个界面只有固定数量控件,不会占用过多内存。
  4. 图片数据尽量放在内存里。图片缓存不要全部放进闪存,尽量放进内存,当内存储存一定数量后再回写。内存操作性能远远高于闪存,频繁的的闪存操作性能很低。

最后还有一个牺牲体验提升性能的方案。对于部分低配置设备(如iPhone3GS,iPad1)等,采用滑动过程不加载,滑动停止才加载的方案。

热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号