一、SDWebImage介紹
相信從事iOS開發(fā)的各位童鞋對(duì)于SDWebImage已經(jīng)是非常熟悉了,那么接下來我們就進(jìn)行一些對(duì)于SDWebImage的小總結(jié),了解一下SDWebImage內(nèi)部都做了一些什么操作,完成了什么牛逼的功能,可以讓眾多下載圖片的操作同時(shí)進(jìn)行。
二、SDWebImage操作步驟
在使用SDWebImage的時(shí)候,我們使用的方法一般都是- (void)sd_setImageWithURL:(NSURL *)url,或者是- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder,但是無論是哪一個(gè)方法,它們內(nèi)部都是調(diào)用的- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock方法,這個(gè)方法就是SDWebImage的核心部分。那我們就看一下這個(gè)方法內(nèi)部都做了一些什么呢
1.[self sd_cancelCurrentImageLoad];首先是調(diào)用內(nèi)部封裝好的方法,將之前該ImageView進(jìn)行的下載操作全部取消,當(dāng)然這個(gè)方法內(nèi)部還是實(shí)現(xiàn)了很多邏輯的,這個(gè)我們?cè)诤竺娴膶?shí)現(xiàn)細(xì)節(jié)里面再細(xì)說,如果你只是來做一個(gè)了解的,那么你可以只看主線劇情。
2.objc_setAssociatedObject(self, &imageURLKey, url, OBJC_ASSOCIATION_RETAIN_NONATOMIC);通過runtime的方法,給每一個(gè)要進(jìn)行下載圖片操作的imageView通過一個(gè)imageURLKey來增加一個(gè)url屬性。
3.if (!(options & SDWebImageDelayPlaceholder)) {
dispatch_main_async_safe(^{
self.image = placeholder;
});?
}。先設(shè)置好占位圖片
4.接下來也就是最關(guān)鍵的部分了,當(dāng)url傳入的情況下,調(diào)用一個(gè)已經(jīng)封裝好的方法,idoperation = [SDWebImageManager.sharedManager downloadImageWithURL:url options:options progress:progressBlock completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL),獲得一個(gè)operation,而獲得這個(gè)operation的過程,就是SDWebImage的核心部分。
第一步
判斷URL是否合法,如果不合法那么就置空。最后也就和錯(cuò)誤一起返回了。
if ([url isKindOfClass:NSString.class]) {
url = [NSURL URLWithString:(NSString *)url];
}
if (![url isKindOfClass:NSURL.class]) {
url = nil;
}
第二步
創(chuàng)建一個(gè)操作,并且查看,在已經(jīng)下載失敗的url中,是否包含這個(gè)url,通過這些標(biāo)記,來判斷下載操作是否可以正常進(jìn)行下去。然后在加鎖的情況下,將操作添加到操作數(shù)組中
__block SDWebImageCombinedOperation *operation = [SDWebImageCombinedOperation new];
__weak SDWebImageCombinedOperation *weakOperation = operation;
BOOL isFailedUrl = NO;
@synchronized (self.failedURLs) {
isFailedUrl = [self.failedURLs containsObject:url];
}
if (!url || (!(options & SDWebImageRetryFailed) && isFailedUrl)) {
dispatch_main_sync_safe(^{
NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorFileDoesNotExist userInfo:nil];
completedBlock(nil, error, SDImageCacheTypeNone, YES, url);
});
return operation;
}
@synchronized (self.runningOperations) {
[self.runningOperations addObject:operation];
}
第三步(核心部分,也是項(xiàng)目中你有可能要對(duì)SDWebImage做修改比較多的部分)
從緩存中獲取對(duì)應(yīng)下載操作的key
根據(jù)這個(gè)key是不是存在,來判斷在內(nèi)存緩存中是不是可以找到對(duì)應(yīng)的圖片
NSString *key = [self cacheKeyForURL:url];
operation.cacheOperation = [self.imageCache queryDiskCacheForKey:key done:^(UIImage *image, SDImageCacheType cacheType) {}
- (NSOperation *)queryDiskCacheForKey:(NSString *)key done:(SDWebImageQueryCompletedBlock)doneBlock {
if (!doneBlock) {
return nil;
}
if (!key) {
doneBlock(nil, SDImageCacheTypeNone);
return nil;
}
NSString *newKey = [self getCacheKey:key];(這個(gè)方法一般是我們自己來自定義修改key的,比如你公司自己定義的key)
通過這個(gè)newlkey從內(nèi)存緩存中找對(duì)應(yīng)的圖片
// First check the in-memory cache...
UIImage *image = [self imageFromMemoryCacheForKey:newKey];
if (image) {
doneBlock(image, SDImageCacheTypeMemory);
return nil;
}
如果找到了,那么久執(zhí)行block,把圖片回傳,操作結(jié)束
如果找不到,那么就創(chuàng)建新的操作。如果操作被取消了,那么就直接返回
NSOperation *operation = [NSOperation new];
dispatch_async(self.ioQueue, ^{
if (operation.isCancelled) {
return;
}
如果在內(nèi)存緩存中沒有找到,并且下載操作還沒有被取消的話,那么就根據(jù)newkey從磁盤緩存中查找對(duì)應(yīng)的image。如果找到了,那么就存儲(chǔ)到內(nèi)存緩存中,當(dāng)下一次再查找相同圖片的時(shí)候就可以直接從內(nèi)存緩存中取,提高效率。
@autoreleasepool {
UIImage *diskImage = [self diskImageForKey:newKey];
if (diskImage && self.shouldCacheImagesInMemory) {
NSUInteger cost = SDCacheCostForImage(diskImage);
[self.memCache setObject:diskImage forKey:newKey cost:cost];
}
dispatch_async(dispatch_get_main_queue(), ^{
doneBlock(diskImage, SDImageCacheTypeDisk);
});
}
});
主要的過程基本上就是這樣。當(dāng)然其中還有很多的小細(xì)節(jié),比如說清除磁盤緩存啊,怎么樣保證異步下載的數(shù)據(jù)安全啊等等很多,里面也有很多我沒有仔細(xì)看的方法,在不斷的深入過程當(dāng)中我們?cè)倮^續(xù)研究,看一下其他人的代碼是怎么寫的,對(duì)于我們開闊思路還是很有幫助的。希望大家多多溝通交流。