于之前一直維護新浪博客,大量的東西都在這里捡偏,實在不想更換其他博客了唤冈,怎奈新浪對代碼的排版,蛋疼至極银伟,我盡量排版清晰些你虹;
閑著沒事,嘗試用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)存飆升問題慰照;