讀SDWebImage原始碼第三次的收穫與思考(三)
//這篇文章接著上篇 分析 第五步:
全部程式碼為:
- (void)main
{
if (self.isCancelled)
{
return;
}
NSData *data = [[NSData alloc] initWithContentsOfURL:url];
UIImage *image = [[UIImage alloc] initWithData:data];
[data release];
if (!self.isCancelled)
{
[delegate performSelectorOnMainThread:@selector(downloadFinishedWithImage:) withObject:image waitUntilDone:YES];
}
if (cacheInQueue == nil)
{
cacheInQueue = [[NSOperationQueue alloc] init];
[cacheInQueue setMaxConcurrentOperationCount:2];
}
NSString *cacheKey = [url absoluteString];
DMImageCache *imageCache = [DMImageCache sharedImageCache];
// Store image in memory cache NOW, no need to wait for the cache-in operation queue completion
[imageCache storeImage:image forKey:cacheKey toDisk:NO];
// Perform the cache-in in another operation queue in order to not block a download operation slot
NSInvocation *cacheInInvocation = [NSInvocation invocationWithMethodSignature:[[imageCache class] instanceMethodSignatureForSelector:@selector(storeImage:forKey:)]];
[cacheInInvocation setTarget:imageCache];
[cacheInInvocation setSelector:@selector(storeImage:forKey:)];
[cacheInInvocation setArgument:&image atIndex:2];
[cacheInInvocation setArgument:&cacheKey atIndex:3];
[cacheInInvocation retainArguments];
NSInvocationOperation *cacheInOperation = [[NSInvocationOperation alloc] initWithInvocation:cacheInInvocation];
[cacheInQueue addOperation:cacheInOperation];
[cacheInOperation release];
[image release];
}
接下來繼續這一句來分析:
if (!self.isCancelled) { [delegate performSelectorOnMainThread:@selector(downloadFinishedWithImage:) withObject:image waitUntilDone:YES]; }
isCancelled : 判斷操作是否已經標記為取消。
delegate:
DMWebImageView *delegate;
@interface DMWebImageView : UIImageView
如果操作沒有取消, 利用 DMWebImageView 的影象物件去呼叫 downloadFinishedWithImage 方法 但是要通過:performSelectorOnMainThread
// performSelectorOnMainThread的作用就如其名,是在主執行緒執行某個selector, 所有的UIKit裡的呼叫必須是在主執行緒的,在非主執行緒呼叫會產生非預期的結果也很可能會造成crash,所以當你在其他執行緒想執行一段UI呼叫的程式碼時,就需要用到這個方法了
把當前image傳過去:
- (void)downloadFinishedWithImage:(UIImage *)anImage
{
self.image = anImage;
[currentOperation release];
currentOperation = nil;
}
執行完畢以後 ,目前 第一次載入顯示就完全可以了。
接下來第六步:
if (cacheInQueue == nil)
{
cacheInQueue = [[NSOperationQueue alloc] init];
[cacheInQueue setMaxConcurrentOperationCount:2];
}
static NSOperationQueue *cacheInQueue;
如果 cacheInQueue 為空,則建立一個,與下載的佇列物件一樣 設定setMaxConcurrentOperationCount。
NSString *cacheKey = [url absoluteString];
快取key 為 url 的完整url字串。
第七步:
DMImageCache *imageCache = [DMImageCache sharedImageCache];
建立:@interface DMImageCache : NSObject 單例類。
第八步:
//Store image in memory cache NOW, no need to wait for the cache-in operation queue completion
//現在將映像儲存在記憶體快取中,不需要等待快取入操作佇列完成
[imageCache storeImage:image forKey:cacheKey toDisk:NO];
- (void)storeImage:(UIImage *)image forKey:(NSString *)key toDisk:(BOOL)toDisk
{
if (image == nil)
{
return;
}
[cache setObject:image forKey:key];
if (toDisk)
{
[[NSFileManager defaultManager] createFileAtPath:[self cachePathForKey:key] contents:UIImageJPEGRepresentation(image, 1.0) attributes:nil];
}
}
利用單例模式來構建快取,cache是一個可變字典。由於 這部分沒有涉及到 toDIsk 硬碟的狀態,我們就接著看下面的部分:
// Perform the cache-in in another operation queue in order to not block a download operation slot
//在另一個操作佇列中執行快取,以避免阻塞下載操作插槽
NSInvocation *cacheInInvocation = [NSInvocation invocationWithMethodSignature:[[imageCache class] instanceMethodSignatureForSelector:@selector(storeImage:forKey:)]];
[cacheInInvocation setTarget:imageCache];
[cacheInInvocation setSelector:@selector(storeImage:forKey:)];
[cacheInInvocation setArgument:&image atIndex:2];
[cacheInInvocation setArgument:&cacheKey atIndex:3];
[cacheInInvocation retainArguments];
NSInvocationOperation *cacheInOperation = [[NSInvocationOperation alloc] initWithInvocation:cacheInInvocation];
[cacheInQueue addOperation:cacheInOperation];
[cacheInOperation release];
[image release];