您好,匿名用户
随意问技术百科期待您的加入

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

+1 投票

我的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差不多

用户头像 提问 2012年 12月1日 @ Fiddlesticks 上等兵 (242 威望)
分享到:

1个回答

+1 投票
 
最佳答案

最近从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);

把图片变小:

CGSize newSize=CGSizeMake(80, 80);
UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0);
[img drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
用户头像 回复 2012年 12月1日 @ Dr. Mundo 上等兵 (281 威望)
选中 2012年 12月1日 @Fiddlesticks
提一个问题:

相关问题

0 投票
1 回复 36 阅读
0 投票
1 回复 39 阅读
用户头像 提问 2012年 12月1日 @ Aphrodite 上等兵 (185 威望)
0 投票
1 回复 214 阅读
用户头像 提问 2012年 12月1日 @ Lucia 上等兵 (416 威望)
0 投票
1 回复 2 阅读
0 投票
1 回复 34 阅读
用户头像 提问 2012年 12月1日 @ Udyr 上等兵 (341 威望)

欢迎来到随意问技术百科, 这是一个面向专业开发者的IT问答网站,提供途径助开发者查找IT技术方案,解决程序bug和网站运维难题等。
温馨提示:本网站禁止用户发布与IT技术无关的、粗浅的、毫无意义的或者违法国家法规的等不合理内容,谢谢支持。

欢迎访问随意问技术百科,为了给您提供更好的服务,请及时反馈您的意见。
...