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