1. 程式人生 > >讀SDWebImage原始碼第三次的收穫與思考(三)

讀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];