SDWebImage加載.gif 內(nèi)存狂飆問題

于之前一直維護新浪博客,大量的東西都在這里,實在不想更換其他博客了,怎奈新浪對代碼的排版,蛋疼至極,我盡量排版清晰些;

閑著沒事,嘗試用SD加載 .jif,在Cell里加載了大量的.jif,加載完成后意外出現(xiàn)了,內(nèi)存狂飆到 700M+,滑動Cell會下降,大概到150M左右(所用的 .jif 本身比較大); 這個不能忍,于是各種解決:
在測試過程中發(fā)現(xiàn)SD 對混合圖層的處理也不是很到位;不管是動態(tài)圖還是靜態(tài)圖,都未做混合圖層處理;

順便提一下混合圖層:
Color Copied Images:該選項可以給繪制時被Core Animation復(fù)制的圖片添加藍綠色疊加層
Color Misaligned Images:如果圖片邊界沒有與目標(biāo)像素完美對齊,該功能可為圖片疊加上一層品紅色。如果圖
片使用確定的比例大小繪制,那么該功能會為圖片添加一層黃色疊加。

原因概述: SD在對 .jif 的處理過程中采用了一個數(shù)組存儲 jif 的幀圖片,然而并沒有及時釋放;注意文中標(biāo)注”
“的地方;
解決方案: 1. 采用YY_WebImage框架,
2. 在使用SDWebImage加載較多圖片造成內(nèi)存警告時,定期調(diào)用 [[SDImageCache sharedImageCache] setValue:nil forKey:@"memCache"]; 比如tableView加載更多的時候;

這里只介紹方案二:

1.首先分析SD加載 jif 的過程:
sd_animatedGIFNamed是SDWebImage提供的加載gif圖片的一種方法。我們點進去這個方法去看以下。

sd_animatedGIFNamed 這個方法的實現(xiàn)如下。生成一個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"];
    //圖片轉(zhuǎn)換為
    data NSData *data = [NSData dataWithContentsOfFile:retinaPath];
    //如果圖片存在
    if (data) {
    //調(diào)用sd_animatedGIFWithData 生成image實例
    return [UIImage sd_animatedGIFWithData:data]; }
    //如果@2x圖片不存在 讀取普通圖片
    NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:@"gif"];
    //圖片轉(zhuǎn)換為
    data data = [NSData dataWithContentsOfFile:path];
    //如果圖片存在
    if (data) {
    //調(diào)用sd_animatedGIFWithData 生成image實例
    return [UIImage sd_animatedGIFWithData:data]; }
    //如果圖片不存在
    return [UIImage imageNamed:name]; }
    else { //如果不是高清屏 讀取普通圖片
    NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:@"gif"]; //圖片轉(zhuǎn)換為data
    NSData *data = [NSData dataWithContentsOfFile:path];
    //如果圖片存在
    if (data) {
    //調(diào)用sd_animatedGIFWithData 生成image實例
    return [UIImage sd_animatedGIFWithData:data]; }
    //如果圖片不存在
    return [UIImage imageNamed:name]; } }

注釋已經(jīng)很詳細了,這個類方法里面主要是確定當(dāng)前設(shè)備的分辨率,以便加載不同分辨率的圖片。
然后通過sd_animatedGIFWithData 后續(xù)處理
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 {
    // 注意這里的數(shù)組:
    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];
    // 數(shù)組不斷的添加幀圖片,然而并沒有及時釋放
    [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是對圖像數(shù)據(jù)讀取任務(wù)的抽象,通過它可以獲得圖像對象、縮略圖、圖像的屬性(包括Exif信息)。
    那么這行代碼可以這樣理解:通過nadata取到圖像的以系列信息。
    再看size_t count = CGImageSourceGetCount(source);
    這行代碼是讀取CGImageSourceRef有幾個圖片對象。
    下面就不難理解了,
    CGImageSourceCreateImageAtIndex :從source里面讀取各個圖片放入數(shù)組里面。
    讀取顯示圖片的 時間:
    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;
    }
    最后:
    從數(shù)組中讀取幀圖片并顯示:
    animatedImage = [UIImage animatedImageWithImages:images duration:duration];
    播放數(shù)組里里面的圖片。
    從以上分析中可以知道: SD在處理 jif 的時候 采用數(shù)組暫存了 jif 的幀圖片,并未及時釋放,最終導(dǎo)致內(nèi)存飆升問題;
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容