SDWebImage源碼解析及輕量級SDWebImage復(fù)現(xiàn)(附源碼)

讀完這篇文章你可以自己寫一個(gè) 輕量級別的SDWebImage神器真朗,這篇文章類似源碼解析望蜡。但不同的是,不僅僅是解析颗味,會帶你手把手?jǐn)]一個(gè)精簡版的SDWebImage,更深刻的理解SDWebImage的架構(gòu)和一些核心類的功能勋桶。學(xué)習(xí)一個(gè)東西必須要總結(jié)一次才能更加理解其中的精華脱衙,否則即便是讀完了源碼也學(xué)不到多少核心的動心。好記性不如爛筆頭例驹。

注:SDWebImage有很多功能捐韩,我這里就實(shí)現(xiàn)了一個(gè)核心的功能,多圖異步下載鹃锈、內(nèi)存緩存荤胁、磁盤緩存。

輕量級仿SDWebImage源碼下載鏈接:https://github.com/ZhengYaWei1992/ZWWebImageCache

就直接從功能實(shí)現(xiàn)開始屎债,仿SDWebImage架構(gòu)手把手?jǐn)]一個(gè)輕量級SDWebImage仅政,之后在針對SDWebImage框架深入分析,因?yàn)榍捌诘膶?shí)現(xiàn)都是模仿SDWebImage的實(shí)現(xiàn)盆驹,所以當(dāng)你看懂前面的部分后圆丹,再去理解SDWebImage就是太輕而易舉的事了。

一躯喇、輕量級SDWebImage的實(shí)現(xiàn)

1.1 辫封、仿SDWebImage的架構(gòu)設(shè)計(jì)思路

先總的看一下架構(gòu)設(shè)計(jì)思路,如下圖:

仿SDWebImage的架構(gòu)設(shè)計(jì)思路

這個(gè)圖可以先從Controller看起廉丽,Controller主要是否則調(diào)用UIImageView扥類中的方法倦微,相信大家都知道SDWebImage最基本的設(shè)置圖像的方法,需要導(dǎo)入U(xiǎn)IImageView+webCache這個(gè)分類正压,這個(gè)架構(gòu)同樣是采用這種方法欣福,通過UIImageView的分類設(shè)置圖像,只用簡單的傳入一個(gè)urlString即可焦履,當(dāng)然占位圖是必然支持的拓劝。

下載操作類:

UIImageView分類中包含下載操作管理類雏逾,下載操作管理類被設(shè)計(jì)為一個(gè)單例對象,它是這個(gè)架構(gòu)中的核心郑临,緩存校套、下載操作都是由它同意進(jìn)行管理。因?yàn)榫彺骖惐旧砩婕皟?nèi)容不是很多牧抵,所以這里就沒有給緩存類單獨(dú)抽離開來。

下載操作類:

首先要說明一下侨把,圖片的異步下載犀变,這里主要是通過NSOperationQueue這個(gè)類實(shí)現(xiàn)的。所謂的下載類就是NSOperation秋柄,每一個(gè)操作都對應(yīng)一個(gè)實(shí)例對象获枝。下載操作類的實(shí)現(xiàn),這里主要是自定義一個(gè)類繼承自NSOperation骇笔,自定義下載操作省店。 它同樣是由下載操作管理類進(jìn)行管理。
#######關(guān)于緩存:
SDWebImage的緩存形式實(shí)際上是包含內(nèi)存緩存和磁盤緩存笨触。其中內(nèi)存緩存主要是借助NSCache這個(gè)類實(shí)現(xiàn)的懦傍,磁盤緩存就是常規(guī)的文件讀取啦。同樣這個(gè)輕量級的SDWebImage內(nèi)存緩存也是借助NSCache這個(gè)類實(shí)現(xiàn)的芦劣。關(guān)于NSCache這個(gè)類粗俱,可能日常開發(fā)中用的不是很普遍,但使用起來還是很簡單的虚吟,基本使用形式和字典類似寸认,但是又有很多和字典不同之處。這篇文章中會說一些NSCache的使用和注意事項(xiàng)串慰。

1.2 下載操作類的實(shí)現(xiàn)

下載操作類實(shí)際是一個(gè)繼承與 NSOperation的自定義類偏塞,該類中主要有兩個(gè)核心方法:初始化對象和系統(tǒng)方法main。說明:main方法是系統(tǒng)方法邦鲫,在操作添加到隊(duì)列的時(shí)候會調(diào)用此方法灸叼。對外提供了兩個(gè)屬性圖片的urlString以及下載完成的回調(diào)(主要是在main方法中實(shí)現(xiàn))。
操作初始化方法

+ (instancetype)downloaderOperationWithURLString:(NSString *)urlString finishedBlock:(void (^)(UIImage *image))finishedBlock{
    ZWDownloadOperation *op = [[ZWDownloadOperation alloc]init];
    op.urlString = urlString;
    op.finishedBlock = finishedBlock;
    return op;
}

重寫系統(tǒng)main方法掂碱,當(dāng)外部將該類的實(shí)例對象添加到隊(duì)列中時(shí)怜姿,會調(diào)用mian方法。main方法中之所以會出現(xiàn)自動autoreleasepool疼燥,主要是因?yàn)楫惒讲僮鳠o法訪問主線程的自動釋放池沧卢,所以要手動自己添加釋放池。調(diào)用此方法會將讀取的圖片緩到磁盤中醉者,下載完成后但狭,會回到主線程產(chǎn)生回調(diào)披诗,并返回UIImage對象。

//重寫main方法  操作添加到隊(duì)列的時(shí)候會調(diào)用該方法
- (void)main{
    //創(chuàng)建自動釋放池:因如果是異步操作立磁,無法訪問主線程的自動釋放池
    @autoreleasepool {
        //斷言
        //添加斷言后呈队,if (self.finishedBlock) 不用再設(shè)置,如果為空了唱歧,程序會崩潰宪摧,同時(shí)會提醒:finishedBlock不能為空
        NSAssert(self.finishedBlock != nil, @"finishedBlock不能為空");
        
        //下載網(wǎng)絡(luò)圖片
        NSURL *url = [NSURL URLWithString:self.urlString];
        NSData *data = [NSData dataWithContentsOfURL:url];
        //緩存到沙盒中
        if (data) {
            [data writeToFile:[self.urlString appendCacheDir] atomically:YES];
        }
        //這里是子線程
        //NSLog(@"下載圖片 %@ %@",self.urlString,[NSThread currentThread]);
        NSLog(@"從網(wǎng)絡(luò)下載圖片");

        //判斷?操作是否被取消
        //如果取消,直接return颅崩。放在耗時(shí)操作之后和合理一些几于,取消操作的時(shí)候,不會攔截耗時(shí)操作沿后,耗時(shí)操作依然可以執(zhí)行沿彭。下次想顯示圖像的時(shí)候,耗時(shí)操作也執(zhí)行完畢
        if (self.isCancelled) {
            return;
        }
        //圖片下載完成回到主線程更新UI  通過使用斷言尖滚,這里就不用使用if (self.finishedBlock) 判斷了
        //if (self.finishedBlock) {
            [[NSOperationQueue mainQueue]addOperationWithBlock:^{
                UIImage *img = [UIImage imageWithData:data];
                self.finishedBlock(img);
            }];
        //}
    }
}

1.3 下載操作管理類

毫無疑問喉刘,這個(gè)類必然是單例對象,管理類嗎漆弄,當(dāng)然要全局管理睦裳,有足夠高的權(quán)限才能夠被稱為管理者。這個(gè)類主要是對完提供了三個(gè)方法:1撼唾、創(chuàng)建單例對象 2推沸、開啟下載任務(wù) 3、取消操作券坞,因?yàn)橐紤]到重復(fù)下載的情況鬓催,所以要對外提供這樣一個(gè)接口。

說是下載操作管理類恨锚,實(shí)際上是有點(diǎn)不合適的宇驾,應(yīng)為該類主要用有兩個(gè)功能:管理全局下載和管理全局緩存。全局緩存沒有單獨(dú)抽離出來猴伶,暫時(shí)就稱為下載操作管理類就行课舍,緩存會單獨(dú)講解一些的。實(shí)際SDWebImage的緩存功能室單獨(dú)抽取出來的他挎。

下載操作管理類主要提供了這樣三個(gè)屬性筝尾。分別是全局隊(duì)列、下載操作緩存池办桨、圖片內(nèi)存緩存池筹淫。之所以會有下載操作緩存池,是因?yàn)橐涗浵螺d操作呢撞,如果下載操作已經(jīng)存在就不用再去執(zhí)行下載方法损姜,直接reture饰剥,避免重復(fù)下載這種情況的出現(xiàn)。開始下載圖片的時(shí)候摧阅,將草案做添加到操作緩存翅中汰蓉。圖片下載完成后,操作要從操作緩存池中移除棒卷。

//全局隊(duì)列
@property(nonatomic,strong)NSOperationQueue *queue;
//下載操作緩存池   這里不能改為NSCache顾孽,因?yàn)槭盏絻?nèi)存警告后NSCache移除所有對象,之后NSCache中就無法繼續(xù)添加數(shù)據(jù)了
@property(nonatomic,strong)NSMutableDictionary *operationCache;
//圖片緩存池(內(nèi)存緩存)  從字典改為NSCache
@property(nonatomic,strong)NSCache *imageCache;
下載方法的實(shí)現(xiàn)比规。

總的思路是這樣的岩齿,先判斷下載操作是否存在,如存在直接返回苞俘,避免重復(fù)下載。之后根據(jù)圖片地址urlString判斷是否存在內(nèi)存緩存和磁盤緩存龄章,如果存在直接調(diào)用回調(diào)吃谣,如過不存在就創(chuàng)建操作對象,添加到全局隊(duì)列做裙,開啟下載任務(wù)岗憋。

- (void)downloadWithURLString:(NSString *)urlString finishedBlock:(void (^)(UIImage *image))finishedBlock{
    //斷言
    NSAssert(finishedBlock != nil, @"finishedBlock不能為空");
    //如果下載操作已經(jīng)存在,直接返回锚贱。避免重復(fù)下載
    if (self.operationCache[urlString]) {
        return;
    }
    //判斷圖片是否有緩存(內(nèi)存和磁盤緩存)
    if ([self checkImageCache:urlString]) {
        //如果有緩存仔戈,就要回調(diào)設(shè)置圖像
        finishedBlock([self.imageCache objectForKey:urlString]);
        return;
    }
    
    ZWDownloadOperation *op = [ZWDownloadOperation downloaderOperationWithURLString:urlString finishedBlock:^(UIImage *image) {
        //回調(diào)
        finishedBlock(image);
        
        //緩存圖片(內(nèi)存緩存)
        //self.imageCache[urlString] = image;
        [self.imageCache setObject:image forKey:urlString];
        //下載完成,移除緩存的操作
        [self.operationCache removeObjectForKey:urlString];
    }];
    [self.queue addOperation:op];
    //緩存下載操作
    self.operationCache[urlString] = op;
}
關(guān)于取消操作拧廊。

取消操作中藥判斷urlString是否為空监徘,如果不做此判斷,當(dāng)urlString為nil的時(shí)候吧碾,執(zhí)行 [self.operationCache removeObjectForKey:urlString];會發(fā)生崩潰凰盔。

//取消操作
- (void)cancelOperation:(NSString *)urlString{
    //避免第一次urlString為空,然后調(diào)用[self.operationCache removeObjectForKey:urlString]導(dǎo)致崩潰的問題
    if (urlString == nil) {
        return;
    }
    [self.operationCache[urlString] cancel];
    //從緩存池移除操作
    [self.operationCache removeObjectForKey:urlString];
}
關(guān)于緩存倦春。

對于緩存要明確明白分為內(nèi)存緩存和磁盤還盤户敬,在調(diào)用該類執(zhí)行下載操作的時(shí)候,要首先判斷是否有緩存睁本。有緩存就回調(diào)緩存圖片尿庐,無緩存就執(zhí)行下載。但是內(nèi)存緩存和磁盤緩存也是有一些注意的地方呢堰,判斷是否有緩存應(yīng)該判斷是否有內(nèi)存緩存抄瑟,如果有直接回調(diào);如果沒再去判斷是否有磁盤緩存枉疼。如果有磁盤緩存锐借,直接回調(diào)问麸,并將磁盤緩存圖像添加到圖像緩存中,下次再去判斷這張圖片的時(shí)候就可以從內(nèi)存緩存池中讀取钞翔。如果磁盤沒有緩存严卖,最后在開啟下載圖片任務(wù)。

//檢查是否有緩存(內(nèi)存緩存和磁盤緩存)
- (BOOL) checkImageCache:(NSString *)urlString{
    //1布轿、檢查內(nèi)存緩存
    if ([self.imageCache objectForKey:urlString]) {
        NSLog(@"從內(nèi)存中加載");
        return YES;
    }
    
    //2哮笆、檢查沙盒緩存
    UIImage *img = [UIImage imageWithContentsOfFile:[urlString appendCacheDir]];
    //NSLog(@"沙盒路徑:%@",[urlString appendCacheDir]);
    if (img) {
        NSLog(@"從沙盒中加載 ");
        //如果沙盒有圖片,要保存到內(nèi)存中============
        //self.imageCache[urlString] = img;
        [self.imageCache setObject:img forKey:urlString];
        return YES;
    }
    return NO;
}
關(guān)于NSCache

NSCache使用起來基本和字典雷士汰扭,但是有一些注意點(diǎn)稠肘,同事功能比字典強(qiáng)大,因?yàn)榭梢栽O(shè)置緩存限額萝毛,當(dāng)超過限額的時(shí)候项阴,會自動移除之前的記錄,然后添加新的記錄笆包』防浚基本使用就是四句代碼。但是對于移除所有數(shù)據(jù)有一點(diǎn)值得注意的庵佣,通常在使用NSCache的時(shí)候可以在didReceiveMemoryWarning收到內(nèi)存警告方法中調(diào)用[self.cache removeAllObjects];這句代碼歉胶。調(diào)用removeAllObjects之后,就無法再次往cache中緩存數(shù)據(jù)巴粪。但是如果不是在收到內(nèi)存警告中removeAllObjects通今,依然是可以正常添加數(shù)據(jù)的。實(shí)際開發(fā)中應(yīng)重視到這一點(diǎn)肛根。

//設(shè)置數(shù)據(jù)限額
_cache.countLimit = 5;
//添加或替換數(shù)據(jù)
 [self.cache setObject:@"sss" forKey:@"a"];
//根據(jù)key獲取數(shù)據(jù)
[self.cache objectForKey:@"a"];
//移除所有數(shù)據(jù)
[self.cache removeAllObjects];

1.4 關(guān)于UIImageView的分類實(shí)現(xiàn)

分類中主要有一個(gè)核心方法辫塌,設(shè)置UIImageView的圖片。直接一行代碼調(diào)用派哲。這里同樣考慮到一點(diǎn)就是頻繁改變UIImageView的圖片璃氢。假設(shè)在控制器的touchBegan方法中每次點(diǎn)擊都會改變imageView的圖片,點(diǎn)擊多少次圖片就會連續(xù)切換多少次狮辽。但是加入不想讓圖片連續(xù)切換一也,只要顯示第一張圖片和最后一張圖片即可,其他中間觸發(fā)時(shí)間的圖片就不要顯示了喉脖,并且取消下載任務(wù)椰苟。為了滿足這個(gè)需要,所以要借助運(yùn)行時(shí)的關(guān)聯(lián)對象增加屬性树叽,記錄當(dāng)前圖片的urlString地址舆蝴。除了這些額外的處理外,核心就是調(diào)用操作管理類中的獲取圖片的方法。實(shí)現(xiàn)代碼如下洁仗。

- (void)zw_setImageWithUrlString:(NSString *)urlString{
    //防止連續(xù)設(shè)置圖片层皱,UIImageView上的圖片頻繁切換
    //判斷當(dāng)前點(diǎn)擊的圖片地址和上一次圖片的地址是否一樣,如果不一樣取消上一次操作
    if (![urlString isEqualToString:self.currentURLString]) {
        //取消上一次操作
        //[self.operationCache[self.currentURLString] cancel];
        [[ZWDownloderOperationManager sharedManager]cancelOperation:self.currentURLString];
    }
    //記錄上一次的圖片地址
    self.currentURLString = urlString;
    //下載圖片
    [[ZWDownloderOperationManager sharedManager]downloadWithURLString:urlString finishedBlock:^(UIImage *image) {
        self.image = image;
    }];
}

關(guān)聯(lián)對象擴(kuò)充屬性赠潦。

- (void)setCurrentURLString:(NSString *)currentURLString{
    objc_setAssociatedObject(self, @"currentURLString", currentURLString, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)currentURLString{
    return  objc_getAssociatedObject(self, @"currentURLString");
}

當(dāng)然還可以在此基礎(chǔ)上擴(kuò)展一個(gè)設(shè)置占位圖的方法叫胖,代碼如下。

- (void)zw_setImageWithUrlString:(NSString *)urlString withPlaceHolderImageName:(NSString *)placeholderStr{
    self.image = [UIImage imageNamed:placeholderStr];
    [self zw_setImageWithUrlString:urlString];
}
見證成果的時(shí)刻

好了她奥,基本就這些代碼瓮增,剩下的直接在控制器中調(diào)用UIImageView分類中的方法即可,直接上效果圖啦哩俭。

成果

二绷跑、SDWebImage框架結(jié)構(gòu)

2.1 SDWebImage中有四個(gè)核心的類,以及一些分類凡资。

四大核心類以及其關(guān)系:

SDWebImageDownloader砸捏、SDWebImageDownloaderOperationSDWebImageManager隙赁、SDImageCache

核心分類:

UIView+WebCacheOperation:主要在這個(gè)類中處理操作
UIButton+WebCache:button上圖片緩存
UIImage+GIF: gif圖片顯示
UIImageView+WebCache:imageView上的圖片緩存
NSData+ImageContentType:獲取文件類型

類的包含關(guān)系:

UIImageView+WebCache中包含SDWebImageManagerUIView+WebCacheOperation垦藏,
SDWebImageManager包含SDWebImageDownloader
SDWebImageManager包含SDImageCache
SDWebImageDownloader包含SDWebImageDownloaderOperation

其中SDWebImageDownloader是負(fù)責(zé)下載的類鸳谜。SDWebImageDownloaderOperation是下載操作類,繼承于NSOperation式廷。SDWebImageDownloader中包含SDWebImageDownloaderOperation的頭文件咐扭,前者依賴于后者。

SDImageCache主要用于緩存處理滑废,緩存處理同樣是分為內(nèi)存緩存和磁盤緩存蝗肪,并定義了 SDImageCacheType枚舉用于區(qū)分緩存類型。

SDWebImageManager中主要包含了SDWebImageDownloaderSDImageCache蠕趁,并且還有一個(gè)創(chuàng)建單例的方法薛闪。這個(gè)類是一個(gè)核心的管理類,將緩存和下載的業(yè)務(wù)邏輯統(tǒng)一在一起俺陋,和我們實(shí)現(xiàn)的輕量級的圖片緩存不同的是豁延,我們將緩存的業(yè)務(wù)邏輯直接放置到管理類中,并沒有單獨(dú)抽取出來腊状。

UIImageView+WebCache分類中包含SDWebImageManagerUIView+WebCacheOperation核心類诱咏。UIImageView+WebCache中有一個(gè)sd_cancelCurrentImageLoad方法,這個(gè)方法主要是在取消當(dāng)前圖片下載缴挖,防止重復(fù)下載操作袋狞。具體實(shí)現(xiàn)放在UIView+WebCacheOperation

整的來說,和我們之前的實(shí)現(xiàn)還是很類似的。實(shí)際上我們實(shí)現(xiàn)的是模仿SDWebImage實(shí)現(xiàn)的一個(gè)簡單的圖片緩存處理苟鸯。??

另外同蜻,SDWebImageDownloader在初始化initialize的時(shí)候添加了一些通知,主要用于監(jiān)聽下載任務(wù)早处,顯示加載指示器湾蔓。

2.2 SDWebImage的緩存

SDWebImage的緩存也是分為內(nèi)存緩存和磁盤緩存:其中內(nèi)存緩存同樣主要是通過NSCache處理。

磁盤緩存處理中會設(shè)置自動清理磁盤空間陕赃,清理周期設(shè)置為一周卵蛉。SDWebImageCache中有這樣一個(gè)屬性,@property (assign, nonatomic) NSInteger maxCacheAge;該屬性默認(rèn)值是一周(kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7)設(shè)置清理磁盤緩存的周期么库。

處理方式傻丝,請看SDWebCache中的- (void)cleanDiskWithCompletionBlock:(SDWebImageNoParamsBlock)completionBlock 方法。這個(gè)方法中首先看到的是異步操作诉儒,因?yàn)樘幚砦募^多時(shí)葡缰,比較消耗資源最好是異步的方式處理。下面的代碼是定時(shí)清理磁盤緩存方法中的部分代碼忱反,思路是獲取到一周前的時(shí)間泛释,再通過NSDate *modificationDate = resourceValues[NSURLContentModificationDateKey]獲取文件的時(shí)間,比較兩個(gè)是時(shí)間温算,如果大于一周的時(shí)間怜校,就將文件路徑添加到urlsToDelete待刪除數(shù)組中,最后遍歷這個(gè)數(shù)組注竿,統(tǒng)一刪除過期資源茄茁。

//獲取一周前的時(shí)間
NSDate *expirationDate = [NSDate dateWithTimeIntervalSinceNow:-self.maxCacheAge];
NSMutableDictionary *cacheFiles = [NSMutableDictionary dictionary];
//用于記錄當(dāng)前文件總大小
NSUInteger currentCacheSize = 0;

NSMutableArray *urlsToDelete = [[NSMutableArray alloc] init];
for (NSURL *fileURL in fileEnumerator) {
   NSDictionary *resourceValues = [fileURL resourceValuesForKeys:resourceKeys error:NULL];

   if ([resourceValues[NSURLIsDirectoryKey] boolValue]) {
       continue;
   }

   NSDate *modificationDate = resourceValues[NSURLContentModificationDateKey];
   if ([[modificationDate laterDate:expirationDate] isEqualToDate:expirationDate]) {
       //獲取到多余一周前的時(shí)間,并添加到帶刪除的數(shù)組中
       [urlsToDelete addObject:fileURL];
       continue;
   }

    NSNumber *totalAllocatedSize = resourceValues[NSURLTotalFileAllocatedSizeKey];
   currentCacheSize += [totalAllocatedSize unsignedIntegerValue];
    [cacheFiles setObject:resourceValues forKey:fileURL];
 }
//刪除超過一周時(shí)間的文件
for (NSURL *fileURL in urlsToDelete) {
      [_fileManager removeItemAtURL:fileURL error:nil];
}

2.3 關(guān)于SDWebImage的幾個(gè)小問題:

1巩割、最大并發(fā)數(shù)多少裙顽?

SDWebImageDownloader.m文件中的init方法中有這樣一行代碼。即最大線程并發(fā)數(shù)為6宣谈,實(shí)際開發(fā)中并不是開啟的線程越多越好愈犹,當(dāng)線程過多的時(shí)候也會影響性能,一般建議線程不要超過8前后闻丑。

_downloadQueue.maxConcurrentOperationCount = 6;
2漩怎、是否支持gif?

支持gif嗦嗡,主要是在UIImage+gif這個(gè)分類中扬卷。這個(gè)類中總共就只有三個(gè)方法。

self.imageView.image = [UIImage sd_animatedGIFNamed:@"1.gif"];

按照如上方式設(shè)置的gif圖片酸钦,在一些情況可能無法正常顯示gif圖片怪得,這個(gè)是新版本SDWebImage的bug咱枉,老版本中不存在這樣的問題。設(shè)置gif圖片最好實(shí)時(shí)通過下面這個(gè)方法徒恋。

 self.imageView.image = [UIImage sd_animatedGIFNamed:@"1.gif"];
 NSString  *filePath = [[NSBundle bundleWithPath:[[NSBundle mainBundle] bundlePath]] pathForResource:@"1.gif" ofType:nil];
 NSData  *imageData = [NSData dataWithContentsOfFile:filePath];
 self.imageView.image = [UIImage sd_animatedGIFWithData:imageData];
3蚕断、如何判斷文件的類型?

NSData+ImageContentType.m中入挣,sd_contentTypeForImageData方法可以獲取到文件的類型亿乳。其中 [data getBytes:&c length:1];是獲取文件的第一個(gè)字節(jié),文件的第一個(gè)字節(jié)中包含文件類型相關(guān)的信息径筏。

+ (NSString *)sd_contentTypeForImageData:(NSData *)data {
    uint8_t c;
    [data getBytes:&c length:1];
    switch (c) {
        case 0xFF:
              return @"image/jpeg";
       case 0x89:
            return @"image/png";
       case 0x47:
             return @"image/gif";
      case 0x49:
      case 0x4D:
            return @"image/tiff";
      case 0x52:
         // R as RIFF for WEBP
           if ([data length] < 12) {
                  return nil;
           }

          NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(0, 12)] encoding:NSASCIIStringEncoding];
         if ([testString hasPrefix:@"RIFF"] && [testString hasSuffix:@"WEBP"]) {
              return @"image/webp";
         }

        return nil;
    }
    return nil;
}

4葛假、磁盤緩存文件名稱是什么?

通過命名空間com.hackemist.SDWebImageCache.隔離區(qū)分滋恬。
為了防止圖片名沖突聊训,根據(jù)MD5計(jì)算。md5的重復(fù)幾率是很小的恢氯。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末带斑,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子勋拟,更是在濱河造成了極大的恐慌勋磕,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件敢靡,死亡現(xiàn)場離奇詭異挂滓,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)啸胧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進(jìn)店門赶站,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人吓揪,你說我怎么就攤上這事亲怠∷疲” “怎么了柠辞?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長主胧。 經(jīng)常有香客問我叭首,道長,這世上最難降的妖魔是什么踪栋? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任焙格,我火速辦了婚禮,結(jié)果婚禮上夷都,老公的妹妹穿的比我還像新娘眷唉。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布冬阳。 她就那樣靜靜地躺著蛤虐,像睡著了一般。 火紅的嫁衣襯著肌膚如雪肝陪。 梳的紋絲不亂的頭發(fā)上驳庭,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天,我揣著相機(jī)與錄音氯窍,去河邊找鬼饲常。 笑死,一個(gè)胖子當(dāng)著我的面吹牛狼讨,可吹牛的內(nèi)容都是我干的贝淤。 我是一名探鬼主播,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼熊楼,長吁一口氣:“原來是場噩夢啊……” “哼霹娄!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起鲫骗,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤犬耻,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后执泰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體枕磁,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年术吝,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了计济。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,703評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡排苍,死狀恐怖沦寂,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情淘衙,我是刑警寧澤传藏,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站彤守,受9級特大地震影響毯侦,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜具垫,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一侈离、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧筝蚕,春花似錦卦碾、人聲如沸铺坞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽康震。三九已至,卻和暖如春宾濒,著一層夾襖步出監(jiān)牢的瞬間腿短,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工绘梦, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留橘忱,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓卸奉,卻偏偏與公主長得像钝诚,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子榄棵,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評論 2 353

推薦閱讀更多精彩內(nèi)容