国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

SDWebImage 源碼閱讀(四)

2019-11-09 14:46:53
字體:
來源:轉載
供稿:網友

這一篇我們來解決最后的問題,使用 SDWebImage 中下載圖片的類 SDWebImageDownloader,這個類學習完以后,我們對 SDWebImage 的理解會更加深刻。

1. 下載圖片

- (id <SDWebImageOperation>)downloadImageWithURL:(NSURL *)url options:(SDWebImageDownloaderOptions)options PRogress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageDownloaderCompletedBlock)completedBlock { __block SDWebImageDownloaderOperation *operation; __weak __typeof(self)wself = self; // 判斷是否為第一次下載,并且存儲 progressBlock 和 completedBlock,詳情見 1.1 [self addProgressCallback:progressBlock completedBlock:completedBlock forURL:url createCallback:^{ // 第一次下載回調用這個block中的代碼 // 圖片下載的超時時間 NSTimeInterval timeoutInterval = wself.downloadTimeout; if (timeoutInterval == 0.0) { timeoutInterval = 15.0; } // In order to prevent from potential duplicate caching (NSURLCache + SDImageCache) we disable the cache for image requests if told otherwise // 創建請求 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:(options & SDWebImageDownloaderUseNSURLCache ? NSURLRequestUseProtocolCachePolicy : NSURLRequestReloadIgnoringLocalCacheData) timeoutInterval:timeoutInterval]; // HTTPShouldHandleCookies 為 YES 表示將 cookies 一起發送至服務器 request.HTTPShouldHandleCookies = (options & SDWebImageDownloaderHandleCookies); // HTTPShouldUsePipelining 為 YES 可以極大的提高網絡性能,但是 HTTPShouldUsePipelining 也有其局限性,就是服務器必須按照收到請求的順序返回對應的數據 request.HTTPShouldUsePipelining = YES; // 設置頭文件 if (wself.headersFilter) { request.allHTTPHeaderFields = wself.headersFilter(url, [wself.HTTPHeaders copy]); } else { request.allHTTPHeaderFields = wself.HTTPHeaders; } // 詳情見 2. SDWebImageDownloaderOperation 核心類 operation = [[wself.operationClass alloc] initWithRequest:request insession:self.session options:options progress:^(NSInteger receivedSize, NSInteger expectedSize) { SDWebImageDownloader *sself = wself; if (!sself) return; __block NSArray *callbacksForURL; dispatch_sync(sself.barrierQueue, ^{ callbacksForURL = [sself.URLCallbacks[url] copy]; }); for (NSDictionary *callbacks in callbacksForURL) { dispatch_async(dispatch_get_main_queue(), ^{ SDWebImageDownloaderProgressBlock callback = callbacks[kProgressCallbackKey]; if (callback) callback(receivedSize, expectedSize); }); } } completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) { SDWebImageDownloader *sself = wself; if (!sself) return; __block NSArray *callbacksForURL; dispatch_barrier_sync(sself.barrierQueue, ^{ callbacksForURL = [sself.URLCallbacks[url] copy]; if (finished) { [sself.URLCallbacks removeObjectForKey:url]; } }); for (NSDictionary *callbacks in callbacksForURL) { SDWebImageDownloaderCompletedBlock callback = callbacks[kCompletedCallbackKey]; if (callback) callback(image, data, error, finished); } } cancelled:^{ SDWebImageDownloader *sself = wself; if (!sself) return; dispatch_barrier_async(sself.barrierQueue, ^{ [sself.URLCallbacks removeObjectForKey:url]; }); }]; // 是否壓縮圖片 operation.shouldDecompressImages = wself.shouldDecompressImages; if (wself.urlCredential) { operation.credential = wself.urlCredential; } else if (wself.username && wself.passWord) { operation.credential = [NSURLCredential credentialWithUser:wself.username password:wself.password persistence:NSURLCredentialPersistenceForSession]; } // 優先級 if (options & SDWebImageDownloaderHighPriority) { operation.queuePriority = NSOperationQueuePriorityHigh; } else if (options & SDWebImageDownloaderLowPriority) { operation.queuePriority = NSOperationQueuePriorityLow; } // 將 operation 加入隊列中 [wself.downloadQueue addOperation:operation]; if (wself.executionOrder == SDWebImageDownloaderLIFOExecutionOrder) { // Emulate LIFO execution order by systematically adding new operations as last operation's dependency // 如果為棧模式,需要添加依賴關系,棧頂完成才能執行下一個 operation [wself.lastAddedOperation addDependency:operation]; wself.lastAddedOperation = operation; } }]; return operation;}

1.1. 存儲 progressBlock 和 completedBlock

- (void)addProgressCallback:(SDWebImageDownloaderProgressBlock)progressBlock completedBlock:(SDWebImageDownloaderCompletedBlock)completedBlock forURL:(NSURL *)url createCallback:(SDWebImageNoParamsBlock)createCallback { // The URL will be used as the key to the callbacks dictionary so it cannot be nil. If it is nil immediately call the completed block with no image or data. if (url == nil) { if (completedBlock != nil) { completedBlock(nil, nil, nil, NO); } return; } // dispatch_barrier_sync : 等待在它前面的多線程執行完再執行這個 dispatch_barrier_sync(self.barrierQueue, ^{ // 判斷是否是第一次下載這個url,如果是第一次下載,將存儲該url BOOL first = NO; if (!self.URLCallbacks[url]) { self.URLCallbacks[url] = [NSMutableArray new]; first = YES; } // Handle single download of simultaneous download request for the same URL // 根據url從self.URLCallbacks字典中取出數組,將傳入的block根據兩個key(kProgressCallbackKey和kCompletedCallbackKey)copy到字典中 NSMutableArray *callbacksForURL = self.URLCallbacks[url]; NSMutableDictionary *callbacks = [NSMutableDictionary new]; if (progressBlock) callbacks[kProgressCallbackKey] = [progressBlock copy]; if (completedBlock) callbacks[kCompletedCallbackKey] = [completedBlock copy]; [callbacksForURL addObject:callbacks]; self.URLCallbacks[url] = callbacksForURL; if (first) { createCallback(); } });}

2. SDWebImageDownloaderOperation 核心類

在上面我們看到的下載圖片方法,并沒有涉及到核心代碼,原來是通過以下初始化來進入 SDWebImageDownloaderOperation 核心類

- (id)initWithRequest:(NSURLRequest *)request inSession:(NSURLSession *)session options:(SDWebImageDownloaderOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageDownloaderCompletedBlock)completedBlock cancelled:(SDWebImageNoParamsBlock)cancelBlock;

我們進入上面初始化方法的實現中看到,在 init 方法中只是對傳入參數的賦值和獲取,基本上是初始化內容,但是下面有個重寫的 start 方法

- (void)start { // 線程同步加鎖,重置 @synchronized (self) { if (self.isCancelled) { self.finished = YES; [self reset]; return; }#if TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_4_0 // 獲取系統的 application Class UIApplicationClass = NSClassFromString(@"UIApplication"); BOOL hasApplication = UIApplicationClass && [UIApplicationClass respondsToSelector:@selector(sharedApplication)]; if (hasApplication && [self shouldContinueWhenAppEntersBackground]) { __weak __typeof__ (self) wself = self; // 獲取單例 UIApplication * app = [UIApplicationClass performSelector:@selector(sharedApplication)]; // 獲取這個后臺線程的表示 UIBackgroundTaskIdentifier self.backgroundTaskId = [app beginBackgroundTaskWithExpirationHandler:^{ __strong __typeof (wself) sself = wself; // 后臺下載時間到了,就會調用這個 block,如果任務仍在下載就進行取消,調用 endBackgroundTask 方法通知系統該 backgroundTaskId 停止,并把 backgroundTaskId 狀態改為無效 if (sself) { [sself cancel]; [app endBackgroundTask:sself.backgroundTaskId]; sself.backgroundTaskId = UIBackgroundTaskInvalid; } }]; }#endif NSURLSession *session = self.unownedSession; if (!self.unownedSession) { // 會話配置 NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration]; sessionConfig.timeoutIntervalForRequest = 15; /** * Create the session for this task * We send nil as delegate queue so that the session creates a serial operation queue for performing all delegate * method calls and completion handler calls. */ // 為此任務創建會話 // 我們發送 nil 作為代理隊列,所以創建 session 用于執行所有 delegate 調用和完成處理程序調用的串行操作隊列。 self.ownedSession = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:nil]; session = self.ownedSession; } self.dataTask = [session dataTaskWithRequest:self.request]; self.executing = YES; self.thread = [NSThread currentThread]; } // 開始 [self.dataTask resume]; if (self.dataTask) { if (self.progressBlock) { self.progressBlock(0, NSURLResponseUnknownLength); } dispatch_async(dispatch_get_main_queue(), ^{ [[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStartNotification object:self]; }); } else { if (self.completedBlock) { self.completedBlock(nil, nil, [NSError errorWithDomain:NSURLErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey : @"Connection can't be initialized"}], YES); } }#if TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_4_0 Class UIApplicationClass = NSClassFromString(@"UIApplication"); if(!UIApplicationClass || ![UIApplicationClass respondsToSelector:@selector(sharedApplication)]) { return; } if (self.backgroundTaskId != UIBackgroundTaskInvalid) { UIApplication * app = [UIApplication performSelector:@selector(sharedApplication)]; [app endBackgroundTask:self.backgroundTaskId]; self.backgroundTaskId = UIBackgroundTaskInvalid; }#endif}

SDWebImage 源碼閱讀終于完事了,最后一章有些不細心,等有時間重新整理一下


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 平潭县| 湘潭县| 盈江县| 尚义县| 富蕴县| 浠水县| 阿克| 河北区| 安宁市| 育儿| 石楼县| 乡城县| 毕节市| 华蓥市| 南漳县| 阿城市| 清河县| 娱乐| 万山特区| 来宾市| 徐水县| 乳山市| 临江市| 汕尾市| 高雄市| 阜平县| 加查县| 疏勒县| 侯马市| 张家口市| 荣昌县| 巢湖市| 海阳市| 舞阳县| 句容市| 德钦县| 泽普县| 泽普县| 山丹县| 云霄县| 湘潭县|