我的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差不多
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号
最近从4s换回3GS,测试TavleView插图非常卡,于是测试了一下,发现initWithContentsOfFile并不是造成卡顿的主凶。因为这个动作本来就不在main queue里边的。而setImage必须是在main queue。于是写代码在本地生成一些更小的缩略图例如原本240px的直接缩放成80px,发现会快得多。
我的解决方法是:
1、写代码在http下载图片的complete block里面顺便把图片缩放成另外一个大小,另存一份。
2、cell for row代码:
//先把id记录下来,这是在cell里面加的property cell.objectIdforThisCell=**这个cell所代表的对象的id**; //在这个block里面的id,到这一步是设置为cell.objectIdforThisCell一样的 NSString *blockObjectid=cell.objectIdforThisCell; dispatch_async(imagequeue, ^{ UIImage *image = [[UIImage alloc] initWithContentsOfFile:小图文件path]; dispatch_async(dispatch_get_main_queue(), ^{ [self setImage:image forState:state]; }); image = [[UIImage alloc] initWithContentsOfFile:大图文件path]; dispatch_async(dispatch_get_main_queue(), ^{ if ([cell.objectIdforThisCell isEqualToString:blockObjectid]) { //关键在这里,当列表拖动速度很快的时候,cell的property已经被修改(因为reuse了),但是blockObjectid在这个线程里面还是旧的。 //当它们****不相等****,这个cell就是刷太快而被另外一个线程用上了,也就是说,这张大图已经不再需要输出到cell里面了(被另外一个线程的另外一张图冲掉了) //这样一来,在列表快速拖动的时候,瞬间把低清晰的图像给贴上去,等拖动速度慢下来之后,再贴高清晰的图,用户也感觉不出来,也不卡了。 [self setImage:image forState:state]; } }); }); dispatch_release(imagequeue);把图片变小:
先在其他线程做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的渲染上。根据我的经验,这种情况造成的卡,有两个点要去优化:
我想这两个问题你都不存在,那么问题就处在你的图片载入顺序不合理。看你的描述不知道你是UITableView还是用UIScrollView实现的瀑布流,如果是UITableView,就没必要用Button了,因为每个Cell都是可点击的。如果是UIScrollView实现的瀑布流,优化余地较大。这里假设你是瀑布流的图片
最后还有一个牺牲体验提升性能的方案。对于部分低配置设备(如iPhone3GS,iPad1)等,采用滑动过程不加载,滑动停止才加载的方案。