麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

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

SDWebImage 源碼閱讀(四)

2019-11-09 13:56: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 源碼閱讀終于完事了,最后一章有些不細心,等有時間重新整理一下


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 一级大片久久 | 91成人精品 | 中午日产幕无线码1区 | 看片一区 | 日本黄色免费观看视频 | 国产精品成人免费一区久久羞羞 | 亚洲91网 | 一级毛片特黄 | 黄色影院在线看 | 男女羞羞在线观看 | 狼伊千合综网中文 | 在线成人免费视频 | 黄色久 | 亚洲精品一区二区三区免 | 国产精品久久久久久久久久大牛 | 青青国产在线视频 | 国产毛片毛片 | 久久久线视频 | 一级黄色毛片a | av电影免费播放 | 99视频观看 | 免费在线观看成人av | 伊人在线| 精品国产91久久久久久久妲己 | 日本视频在线播放 | 男女无遮挡羞羞视频 | 精品一区二区三区毛片 | 中国女人内谢69xxxx天美 | 久久九九热re6这里有精品 | 免费欧美一级视频 | 国产精品亚洲激情 | 日韩午夜一区二区三区 | 欧美成人免费tv在线播放 | 欧美亚洲综合网 | 欧美亚洲国产成人综合在线 | 特黄一区二区三区 | 成人福利在线播放 | 九九热精品在线视频 | 精品一区二区久久久久久久网精 | 久草视频手机在线观看 | 天天看天天摸天天操 |