为了账号安全,请及时绑定邮箱和手机立即绑定

UITableView中大图片加载时卡顿问题

UITableView中大图片加载时卡顿问题

SMILET 2019-03-29 11:00:18
我的UITableView中有若干UIButton,图片存放于本地硬盘,读取到内存后放进UIButton展示。子线程负责从文件读入图片到内存,主线程用setImage:forState:展示。由于setImage:forState:耗时较长且在主线程,导致Table拖动起来较卡。代码如下(UIButton上的扩展):-(void)asyncLoadImageAtPath:(NSString*)fullPathforState:(UIControlState)state{dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{UIImage*image=[[UIImagealloc]initWithContentsOfFile:fullPath];dispatch_async(dispatch_get_main_queue(),^{[selfsetImage:imageforState:state];});});}后将setImage:forState:移入子线程,卡是不卡了,但是setImage:forState线程不安全,setImage:forState调用两秒后才会被显示。代码改为:-(void)asyncLoadImageAtPath:(NSString*)fullPathforState:(UIControlState)state{dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{UIImage*image=[[UIImagealloc]initWithContentsOfFile:fullPath];dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0),^{[selfsetImage:imageforState:state];});});}QQ电影票中存于本地的大图拖起来不卡,且看起来是线程安全的。不知是怎么做的?解决:最后读图重画成小尺寸一个线程,渲染一个线程,性能和自带的Photos差不多
查看完整描述

2 回答

?
绝地无双

TA贡献1946条经验 获得超4个赞

最近从4s换回3GS,测试TavleView插图非常卡,于是测试了一下,发现initWithContentsOfFile并不是造成卡顿的主凶。因为这个动作本来就不在mainqueue里边的。而setImage必须是在mainqueue。于是写代码在本地生成一些更小的缩略图例如原本240px的直接缩放成80px,发现会快得多。我的解决方法是:
1、写代码在http下载图片的completeblock里面顺便把图片缩放成另外一个大小,另存一份。
2、cellforrow代码://先把id记录下来,这是在cell里面加的property
cell.objectIdforThisCell=**这个cell所代表的对象的id**;
//在这个block里面的id,到这一步是设置为cell.objectIdforThisCell一样的
NSString*blockObjectid=cell.objectIdforThisCell;
dispatch_async(imagequeue,^{
UIImage*image=[[UIImagealloc]initWithContentsOfFile:小图文件path];
dispatch_async(dispatch_get_main_queue(),
^{
[selfsetImage:imageforState:state];
});
image=[[UIImagealloc]initWithContentsOfFile:大图文件path];
dispatch_async(dispatch_get_main_queue(),
^{
if([cell.objectIdforThisCellisEqualToString:blockObjectid]){
//关键在这里,当列表拖动速度很快的时候,cell的property已经被修改(因为reuse了),但是blockObjectid在这个线程里面还是旧的。
//当它们****不相等****,这个cell就是刷太快而被另外一个线程用上了,也就是说,这张大图已经不再需要输出到cell里面了(被另外一个线程的另外一张图冲掉了)
//这样一来,在列表快速拖动的时候,瞬间把低清晰的图像给贴上去,等拖动速度慢下来之后,再贴高清晰的图,用户也感觉不出来,也不卡了。
[selfsetImage:imageforState:state];
}
});
});
dispatch_release(imagequeue);把图片变小:CGSizenewSize=CGSizeMake(80,80);
UIGraphicsBeginImageContextWithOptions(newSize,NO,0.0);
[imgdrawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
newImage=UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
                            
查看完整回答
反对 回复 2019-03-29
?
侃侃无极

TA贡献2051条经验 获得超10个赞

先在其他线程做asyncloading,就是其中的initWithContentsOfFile,然后当imageloading完了再调用主线程updateUI.dispatch_queue_timagequeue=dispatch_queue_create("com.company.imageLoadingQueue",NULL);
//Startthebackgroundqueue
dispatch_async(imagequeue,^{
UIImage*image=[[UIImagealloc]initWithContentsOfFile:fullPath];
dispatch_async(dispatch_get_main_queue(),
^{
[selfsetImage:imageforState:state];
});//endofmainthreadqueue
});//endofimagequeue
dispatch_release(imagequeue);
                            
查看完整回答
反对 回复 2019-03-29
  • 2 回答
  • 0 关注
  • 387 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信