SDWebImage加载.gif 内存狂飙问题

于之前一直维护新浪博客,大量的东西都在这里,实在不想更换其他博客了,怎奈新浪对代码的排版,蛋疼至极,我尽量排版清晰些;

闲着没事,尝试用SD加载 .jif,在Cell里加载了大量的.jif,加载完成后意外出现了,内存狂飙到 700M+,滑动Cell会下降,大概到150M左右(所用的 .jif 本身比较大); 这个不能忍,于是各种解决:
在测试过程中发现SD 对混合图层的处理也不是很到位;不管是动态图还是静态图,都未做混合图层处理;

顺便提一下混合图层:
Color Copied Images:该选项可以给绘制时被Core Animation复制的图片添加蓝绿色叠加层
Color Misaligned Images:如果图片边界没有与目标像素完美对齐,该功能可为图片叠加上一层品红色。如果图
片使用确定的比例大小绘制,那么该功能会为图片添加一层黄色叠加。

原因概述: SD在对 .jif 的处理过程中采用了一个数组存储 jif 的帧图片,然而并没有及时释放;注意文中标注”
“的地方;
解决方案: 1. 采用YY_WebImage框架,
2. 在使用SDWebImage加载较多图片造成内存警告时,定期调用 [[SDImageCache sharedImageCache] setValue:nil forKey:@"memCache"]; 比如tableView加载更多的时候;

这里只介绍方案二:

1.首先分析SD加载 jif 的过程:
sd_animatedGIFNamed是SDWebImage提供的加载gif图片的一种方法。我们点进去这个方法去看以下。

sd_animatedGIFNamed 这个方法的实现如下。生成一个UIImage对象。

  • (UIImage *)sd_animatedGIFNamed:(NSString *)name {
    //取到屏幕分辨率
    CGFloat scale = [UIScreen mainScreen].scale;
    //是否是高清屏
    if (scale > 1.0f) {
    //如果是高清屏 取@2x图片 读取图片
    NSString *retinaPath = [[NSBundle mainBundle] pathForResource:[name
    stringByAppendingString:@"@2x"] ofType:@"gif"];
    //图片转换为
    data NSData *data = [NSData dataWithContentsOfFile:retinaPath];
    //如果图片存在
    if (data) {
    //调用sd_animatedGIFWithData 生成image实例
    return [UIImage sd_animatedGIFWithData:data]; }
    //如果@2x图片不存在 读取普通图片
    NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:@"gif"];
    //图片转换为
    data data = [NSData dataWithContentsOfFile:path];
    //如果图片存在
    if (data) {
    //调用sd_animatedGIFWithData 生成image实例
    return [UIImage sd_animatedGIFWithData:data]; }
    //如果图片不存在
    return [UIImage imageNamed:name]; }
    else { //如果不是高清屏 读取普通图片
    NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:@"gif"]; //图片转换为data
    NSData *data = [NSData dataWithContentsOfFile:path];
    //如果图片存在
    if (data) {
    //调用sd_animatedGIFWithData 生成image实例
    return [UIImage sd_animatedGIFWithData:data]; }
    //如果图片不存在
    return [UIImage imageNamed:name]; } }

注释已经很详细了,这个类方法里面主要是确定当前设备的分辨率,以便加载不同分辨率的图片。
然后通过sd_animatedGIFWithData 后续处理
2.再来看看sd_animatedGIFWithData:

  • (UIImage *)sd_animatedGIFWithData:(NSData *)data {
    if (!data) {
    return nil; }
    CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
    size_t count = CGImageSourceGetCount(source);
    UIImage *animatedImage;
    if (count <= 1) {
    animatedImage = [[UIImage alloc] initWithData:data];}
    else {
    // 注意这里的数组:
    NSMutableArray *images = [NSMutableArray array];
    NSTimeInterval duration = 0.0f;
    for (size_t i = 0; i < count; i++) {
    CGImageRef image = CGImageSourceCreateImageAtIndex(source, i, NULL);
    duration += [self frameDurationAtIndex:i source:source];
    // 数组不断的添加帧图片,然而并没有及时释放
    [images addObject:[UIImage imageWithCGImage:image scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp]];
    CGImageRelease(image); }
    if (!duration) {
    duration = (1.0f / 10.0f) * count; }
    animatedImage = [UIImage animatedImageWithImages:images duration:duration]; }
    CFRelease(source); return animatedImage; }
    先看这行代码
    CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
    CGImageSourceRef定义如下,
      typedef struct CGImageSource *CGImageSourceRef;
    可以看到它是一个CGImageSource 指针。
    CGImageSource是个什么东东呢?
    CGImageSource是对图像数据读取任务的抽象,通过它可以获得图像对象、缩略图、图像的属性(包括Exif信息)。
    那么这行代码可以这样理解:通过nadata取到图像的以系列信息。
    再看size_t count = CGImageSourceGetCount(source);
    这行代码是读取CGImageSourceRef有几个图片对象。
    下面就不难理解了,
    CGImageSourceCreateImageAtIndex :从source里面读取各个图片放入数组里面。
    读取显示图片的 时间:
    duration += [self frameDurationAtIndex:i source:source];
    计算图片显示时间:
  • (float)frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source { float frameDuration = 0.1f;
    CFDictionaryRef cfFrameProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil);
    NSDictionary *frameProperties = (__bridge NSDictionary *)cfFrameProperties;
    NSDictionary *gifProperties = frameProperties[(NSString *)kCGImagePropertyGIFDictionary];
    NSNumber *delayTimeUnclampedProp = gifProperties[(NSString *)kCGImagePropertyGIFUnclampedDelayTime];
    if (delayTimeUnclampedProp) {
    frameDuration = [delayTimeUnclampedProp floatValue]; }
    else {
    NSNumber *delayTimeProp = gifProperties[(NSString *)kCGImagePropertyGIFDelayTime];
    if (delayTimeProp) {
    frameDuration = [delayTimeProp floatValue]; } }
    if (frameDuration < 0.011f) {
    frameDuration = 0.100f; }
    CFRelease(cfFrameProperties); return frameDuration;
    }
    最后:
    从数组中读取帧图片并显示:
    animatedImage = [UIImage animatedImageWithImages:images duration:duration];
    播放数组里里面的图片。
    从以上分析中可以知道: SD在处理 jif 的时候 采用数组暂存了 jif 的帧图片,并未及时释放,最终导致内存飙升问题;

你可能感兴趣的:(SDWebImage加载.gif 内存狂飙问题)