n年關了,立刻放假,終於把手頭上的事情告一段落,連續發佈了3個app,我也是醉了。數組
終於有了點時間。想研究下SDWebImage是怎麼加載gif圖片的。app
一直很好奇。指針
如今開始。orm
1,首先咱們看下SDWebImage是怎麼加載gif的。對象
faceButton.image = [UIImage sd_animatedGIFNamed:[NSString stringWithFormat:@"CHATA_%d",i - 46]];
sd_animatedGIFNamed是SDWebImage提供的加載gif圖片的一種方法。咱們點進去這個方法去看如下。
2,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]; } }
註釋已經很詳細了,這個類方法裏面主要是肯定當前設備的分辨率,以便加載不一樣分辨率的圖片。
而後經過
dataWithContentsOfFile
方法把圖片轉換爲NSData,判斷NSData是否存在。
若是存在調用sd_animatedGIFWithData 後續處理。
3,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;blog
能夠看到它是一個CGImageSource 指針。圖片
CGImageSource又是什麼呢?string
CGImageSource是對圖像數據讀取任務的抽象,經過它能夠得到圖像對象、縮略圖、圖像的屬性(包括Exif信息)。it
那麼這行代碼能夠這樣理解:經過nadata取到圖像的以系列信息。io
goon,
size_t count = CGImageSourceGetCount(source);
這行代碼是讀取CGImageSourceRef有幾個圖片對象。
next,下面就不難理解了,
CGImageSourceCreateImageAtIndex 從
source裏面讀取各個圖片放入數組裏面。
讀取顯示圖片的 時間。
duration += [self frameDurationAtIndex:i source:source];
4,計算圖片顯示時間
+ (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; }
詳細分析 待續!!!
5,
animatedImage = [UIImage animatedImageWithImages:images duration:duration];
播放數組裏裏面的圖片。
over!!!!