SDWebImageDownloader和SDWebImageDownloaderOperation 是 SDWebImage的下载类,是SDWebImage的很重要的一个类,这个类主要负责图片的下载,下面我看下具体的代码
SDWebImageDownloaderOptions 枚举
typedef NS_OPTIONS(NSUInteger, SDWebImageDownloaderOptions) {
SDWebImageDownloaderLowPriority = 1 << 0, //图片下载设置低优先级
SDWebImageDownloaderProgressiveDownload = 1 << 1,//分进度下载图片
/**
* By default, request prevent the use of NSURLCache. With this flag, NSURLCache
* is used with default policies.
*/
SDWebImageDownloaderUseNSURLCache = 1 << 2, //设置了该选项则使用NSURLCache缓存策略
/**
* Call completion block with nil image/imageData if the image was read from NSURLCache
* (to be combined with `SDWebImageDownloaderUseNSURLCache`).
*/ //如果图片从NSURLCache读取,则回到block中的image和imageData置为nil
SDWebImageDownloaderIgnoreCachedResponse = 1 << 3,
/**
* In iOS 4+, continue the download of the image if the app goes to background. This is achieved by asking the system for
* extra time in background to let the request finish. If the background task expires the operation will be cancelled.
*/
//在iOS4之后,如果设置了此选项则在后台依然下载图片,申请额外的时间来进行后台下载
SDWebImageDownloaderContinueInBackground = 1 << 4,
/**
* Handles cookies stored in NSHTTPCookieStore by setting
* NSMutableURLRequest.HTTPShouldHandleCookies = YES;
*/
// 处理存储在NSHTTPCookieStore中的cookies
SDWebImageDownloaderHandleCookies = 1 << 5,
/**
* Enable to allow untrusted SSL certificates.
* Useful for testing purposes. Use with caution in production.
*/
//允许非信任的SSL证书
SDWebImageDownloaderAllowInvalidSSLCertificates = 1 << 6,
/**
* Put the image in the high priority queue.
*/
//设置图片下载高优先级
SDWebImageDownloaderHighPriority = 1 << 7,
/**
* Scale down the image
*/
//对大图片进行缩放
SDWebImageDownloaderScaleDownLargeImages = 1 << 8,
};
一些block
typedef void(^SDWebImageDownloaderProgressBlock)(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL);
typedef void(^SDWebImageDownloaderCompletedBlock)(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished);
typedef NSDictionary SDHTTPHeadersDictionary;
typedef NSMutableDictionary SDHTTPHeadersMutableDictionary;
//这个block允许我们自定义请求头,通过Block传值,有一定的优点,我们可以拿到一些参数,然后在加工成我们需要的数据,最后返回。
typedef SDHTTPHeadersDictionary * _Nullable (^SDWebImageDownloaderHeadersFilterBlock)(NSURL * _Nullable url, SDHTTPHeadersDictionary * _Nullable headers);
SDWebImageDownloadToken 是作为下载操作的唯一标识,在创建operation的时候初始化绑定,当需要去cancel操作的时候就需要这个token。
@interface SDWebImageDownloadToken : NSObject
@property (nonatomic, strong, nullable) NSURL *url;
@property (nonatomic, strong, nullable) id downloadOperationCancelToken;
@end
SDWebImageDownloader.h
@interface SDWebImageDownloader : NSObject
/**
* Decompressing images that are downloaded and cached can improve performance but can consume lot of memory.
* Defaults to YES. Set this to NO if you are experiencing a crash due to excessive memory consumption.
*///是否压缩图片
@property (assign, nonatomic) BOOL shouldDecompressImages;
/**
* The maximum number of concurrent downloads
*///设置最大并发数量
@property (assign, nonatomic) NSInteger maxConcurrentDownloads;
/**
* Shows the current amount of downloads that still need to be downloaded
*///获取当前下载的数量
@property (readonly, nonatomic) NSUInteger currentDownloadCount;
/**
* The timeout value (in seconds) for the download operation. Default: 15.0.
*///下载时间 默认15秒
@property (assign, nonatomic) NSTimeInterval downloadTimeout;
/**
* The configuration in use by the internal NSURLSession.
* Mutating this object directly has no effect.
*
* @see createNewSessionWithConfiguration:
*///NSURLSession配置一些请求所需要的策略
@property (readonly, nonatomic, nonnull) NSURLSessionConfiguration *sessionConfiguration;
/**
* Changes download operations execution order. Default value is `SDWebImageDownloaderFIFOExecutionOrder`.
*///设置下载顺序
@property (assign, nonatomic) SDWebImageDownloaderExecutionOrder executionOrder;
/**
* Singleton method, returns the shared instance
*
* @return global shared instance of downloader class
*/
+ (nonnull instancetype)sharedDownloader;
/**
* Set the default URL credential to be set for request operations.
*///设置身份认证
@property (strong, nonatomic, nullable) NSURLCredential *urlCredential;
/**
* Set username
*///设置用户名
@property (strong, nonatomic, nullable) NSString *username;
/**
* Set password
*///设置密码
@property (strong, nonatomic, nullable) NSString *password;
/**
* Set filter to pick headers for downloading image HTTP request.
*
* This block will be invoked for each downloading image request, returned
* NSDictionary will be used as headers in corresponding HTTP request.
*///针对header进行过滤的block
@property (nonatomic, copy, nullable) SDWebImageDownloaderHeadersFilterBlock headersFilter;
/**
* Creates an instance of a downloader with specified session configuration.
* @note `timeoutIntervalForRequest` is going to be overwritten.
* @return new instance of downloader class
*///生成一个实例,利用特定的配置sessionConfiguration
- (nonnull instancetype)initWithSessionConfiguration:(nullable NSURLSessionConfiguration *)sessionConfiguration NS_DESIGNATED_INITIALIZER;
/**
* Set a value for a HTTP header to be appended to each download HTTP request.
*
* @param value The value for the header field. Use `nil` value to remove the header.
* @param field The name of the header field to set.
*///针对request添加HTTP header
- (void)setValue:(nullable NSString *)value forHTTPHeaderField:(nullable NSString *)field;
/**
* Returns the value of the specified HTTP header field.
*
* @return The value associated with the header field field, or `nil` if there is no corresponding header field.
*///返回某个header field的value
- (nullable NSString *)valueForHTTPHeaderField:(nullable NSString *)field;
/**
* Sets a subclass of `SDWebImageDownloaderOperation` as the default
* `NSOperation` to be used each time SDWebImage constructs a request
* operation to download an image.
*
* @param operationClass The subclass of `SDWebImageDownloaderOperation` to set
* as default. Passing `nil` will revert to `SDWebImageDownloaderOperation`.
*///设置一个SDWebImageDownloaderOperation的子类赋值给_operationClass
- (void)setOperationClass:(nullable Class)operationClass;
/**
* Creates a SDWebImageDownloader async downloader instance with a given URL
*
* The delegate will be informed when the image is finish downloaded or an error has happen.
*
* @see SDWebImageDownloaderDelegate
*
* @param url The URL to the image to download
* @param options The options to be used for this download
* @param progressBlock A block called repeatedly while the image is downloading
* @note the progress block is executed on a background queue
* @param completedBlock A block called once the download is completed.
* If the download succeeded, the image parameter is set, in case of error,
* error parameter is set with the error. The last parameter is always YES
* if SDWebImageDownloaderProgressiveDownload isn't use. With the
* SDWebImageDownloaderProgressiveDownload option, this block is called
* repeatedly with the partial image object and the finished argument set to NO
* before to be called a last time with the full image and finished argument
* set to YES. In case of error, the finished argument is always YES.
*
* @return A token (SDWebImageDownloadToken) that can be passed to -cancel: to cancel this operation
*///根据指定的url异步加载图片
- (nullable SDWebImageDownloadToken *)downloadImageWithURL:(nullable NSURL *)url
options:(SDWebImageDownloaderOptions)options
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock;
/**
* Cancels a download that was previously queued using -downloadImageWithURL:options:progress:completed:
*
* @param token The token received from -downloadImageWithURL:options:progress:completed: that should be canceled.
*///取消指定token的下载
- (void)cancel:(nullable SDWebImageDownloadToken *)token;
/**
* Sets the download queue suspension state
*///设置下载队列是否挂起
- (void)setSuspended:(BOOL)suspended;
/**
* Cancels all download operations in the queue
*///取消所有的下载
- (void)cancelAllDownloads;
/**
* Forces SDWebImageDownloader to create and use a new NSURLSession that is
* initialized with the given configuration.
* @note All existing download operations in the queue will be cancelled.
* @note `timeoutIntervalForRequest` is going to be overwritten.
*
* @param sessionConfiguration The configuration to use for the new NSURLSession
*///强制给self设置一个新的NSURLSession
- (void)createNewSessionWithConfiguration:(nonnull NSURLSessionConfiguration *)sessionConfiguration;
/**
* Invalidates the managed session, optionally canceling pending operations.
* @note If you use custom downloader instead of the shared downloader, you need call this method when you do not use it to avoid memory leak
* @param cancelPendingOperations Whether or not to cancel pending operations.
* @note Calling this method on the shared downloader has no effect.
*///取消operation并且session设置为Invalidates
- (void)invalidateSessionAndCancel:(BOOL)cancelPendingOperations;
SDWebImageDownloader 的属性
@interface SDWebImageDownloader ()
@property (strong, nonatomic, nonnull) NSOperationQueue *downloadQueue;//定义下载队列
@property (weak, nonatomic, nullable) NSOperation *lastAddedOperation;//定义下载的上个operation 作用是为了后面的下载依赖
@property (assign, nonatomic, nullable) Class operationClass;// 图片下载操作类
@property (strong, nonatomic, nonnull) NSMutableDictionary *URLOperations;//下载url作为key value是具体的下载operation 用字典来存储,方便cancel等操作
@property (strong, nonatomic, nullable) SDHTTPHeadersMutableDictionary *HTTPHeaders;//HTTP请求头
// This queue is used to serialize the handling of the network responses of all the download operation in a single queue
@property (strong, nonatomic, nullable) dispatch_queue_t barrierQueue;//定义队列用来保证处理所有下载操作线程安全,将任务利用dispatch_barrier_sync队列barrierQueue
// The session in which data tasks will run
//利用NSURLSession进行网络请求
@property (strong, nonatomic) NSURLSession *session;
@end
+initialize在类或者其子类的第一个方法被调用前调用。即使类文件被引用进项目,但是没有使用,initialize不会被调用。由于是系统自动调用,也不需要显式的调用父类的initialize,否则父类的initialize会被多次执行。假如这个类放到代码中,而这段代码并没有被执行,这个函数是不会被执行的。
NSClassFromString,用来判断当前程序是否有指定字符串的类,如果没有回返回一个空对象,id activityIndicator = [NSClassFromString(@"SDNetworkActivityIndicator") performSelector:NSSelectorFromString(@"sharedActivityIndicator")];这样配合对一个不确定进行初始化
如果项目中引用了SDNetworkActivityIndicator,则开启一些关于小菊花的监听
+ (void)initialize {
// Bind SDNetworkActivityIndicator if available (download it here: http://github.com/rs/SDNetworkActivityIndicator )
// To use it, just add #import "SDNetworkActivityIndicator.h" in addition to the SDWebImage import
if (NSClassFromString(@"SDNetworkActivityIndicator")) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
id activityIndicator = [NSClassFromString(@"SDNetworkActivityIndicator") performSelector:NSSelectorFromString(@"sharedActivityIndicator")];
#pragma clang diagnostic pop
// Remove observer in case it was previously added.
[[NSNotificationCenter defaultCenter] removeObserver:activityIndicator name:SDWebImageDownloadStartNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:activityIndicator name:SDWebImageDownloadStopNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:activityIndicator
selector:NSSelectorFromString(@"startActivity")
name:SDWebImageDownloadStartNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:activityIndicator
selector:NSSelectorFromString(@"stopActivity")
name:SDWebImageDownloadStopNotification object:nil];
}
}
初始化方法
//单利
+ (nonnull instancetype)sharedDownloader {
static dispatch_once_t once;
static id instance;
dispatch_once(&once, ^{
instance = [self new];
});
return instance;
}
- (nonnull instancetype)init {
return [self initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
}
- (nonnull instancetype)initWithSessionConfiguration:(nullable NSURLSessionConfiguration *)sessionConfiguration {
if ((self = [super init])) {
_operationClass = [SDWebImageDownloaderOperation class];
_shouldDecompressImages = YES;//是否压缩图片 默认压缩
_executionOrder = SDWebImageDownloaderFIFOExecutionOrder;
_downloadQueue = [NSOperationQueue new];
_downloadQueue.maxConcurrentOperationCount = 6; //最大并发数
_downloadQueue.name = @"com.hackemist.SDWebImageDownloader";
_URLOperations = [NSMutableDictionary new];
#ifdef SD_WEBP
_HTTPHeaders = [@{@"Accept": @"image/webp,image/*;q=0.8"} mutableCopy];
#else
_HTTPHeaders = [@{@"Accept": @"image/*;q=0.8"} mutableCopy];
#endif
_barrierQueue = dispatch_queue_create("com.hackemist.SDWebImageDownloaderBarrierQueue", DISPATCH_QUEUE_CONCURRENT);
_downloadTimeout = 15.0;
[self createNewSessionWithConfiguration:sessionConfiguration];
}
return self;
}
创建session
- (void)createNewSessionWithConfiguration:(NSURLSessionConfiguration *)sessionConfiguration {
[self cancelAllDownloads]; // 先取消 _downloadQueue 队列中的所有任务
if (self.session) {
[self.session invalidateAndCancel];//invalidateAndCancel失效(取消未完成任务)或finishTasksAndInvalidate(允许任务完成之前无效的对象)。
}
sessionConfiguration.timeoutIntervalForRequest = self.downloadTimeout;//设置时间
/**
* 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.
*///delegate设置为自己,也就是当使用这个会话请求数据,收到响应时,会调用SDWebImageDownloader.m中的代理方法,然后再调用SDWebImageDownloaderOperation中的代理方法处理事情。这样做的目的是为了共用一个URLSession
self.session = [NSURLSession sessionWithConfiguration:sessionConfiguration
delegate:self
delegateQueue:nil];
}
session取消下载和dealloc方法
- (void)invalidateSessionAndCancel:(BOOL)cancelPendingOperations {
if (self == [SDWebImageDownloader sharedDownloader]) {
return;
}
if (cancelPendingOperations) {
[self.session invalidateAndCancel]; //取消
} else {
[self.session finishTasksAndInvalidate];//结束
}
}
- (void)dealloc {
[self.session invalidateAndCancel];
self.session = nil;
[self.downloadQueue cancelAllOperations];
}
request header 方法,可以添加,获取请求头
//针对request添加HTTP header
- (void)setValue:(nullable NSString *)value forHTTPHeaderField:(nullable NSString *)field {
if (value) {
self.HTTPHeaders[field] = value;
} else {
[self.HTTPHeaders removeObjectForKey:field];
}
}
//返回某个header field的value
- (nullable NSString *)valueForHTTPHeaderField:(nullable NSString *)field {
return self.HTTPHeaders[field];
}
getter和setter方法
- (void)setMaxConcurrentDownloads:(NSInteger)maxConcurrentDownloads {
_downloadQueue.maxConcurrentOperationCount = maxConcurrentDownloads;
}
- (NSUInteger)currentDownloadCount {
return _downloadQueue.operationCount;
}
- (NSInteger)maxConcurrentDownloads {
return _downloadQueue.maxConcurrentOperationCount;
}
- (NSURLSessionConfiguration *)sessionConfiguration {
return self.session.configuration;
}
设置一个SDWebImageDownloaderOperation的子类赋值给_operationClass
- (void)setOperationClass:(nullable Class)operationClass {
if (operationClass && [operationClass isSubclassOfClass:[NSOperation class]] && [operationClass conformsToProtocol:@protocol(SDWebImageDownloaderOperationInterface)]) {
_operationClass = operationClass;
} else {
_operationClass = [SDWebImageDownloaderOperation class];
}
}
下载图片方法
- (nullable SDWebImageDownloadToken *)downloadImageWithURL:(nullable NSURL *)url
options:(SDWebImageDownloaderOptions)options
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock {
__weak SDWebImageDownloader *wself = self;
//在下面的block中创建operation
return [self addProgressCallback:progressBlock completedBlock:completedBlock forURL:url createCallback:^SDWebImageDownloaderOperation *{
//初始化一个SDWebImageDownloaderOperation 和其他配置
__strong __typeof (wself) sself = wself;
NSTimeInterval timeoutInterval = sself.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
// 2.创建request,注意我们设置的缓存策略的选择,
/*
NSURLRequestUseProtocolCachePolicy = 0 //默认的缓存策略,使用协议的缓存策略
NSURLRequestReloadIgnoringLocalCacheData = 1 //每次都从网络加载
NSURLRequestReturnCacheDataElseLoad = 2 //返回缓存否则加载,很少使用
NSURLRequestReturnCacheDataDontLoad = 3 //只返回缓存,没有也不加载,很少使用
*/
NSURLRequestCachePolicy cachePolicy = options & SDWebImageDownloaderUseNSURLCache ? NSURLRequestUseProtocolCachePolicy : NSURLRequestReloadIgnoringLocalCacheData;
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url
cachePolicy:cachePolicy
timeoutInterval:timeoutInterval];
request.HTTPShouldHandleCookies = (options & SDWebImageDownloaderHandleCookies);
request.HTTPShouldUsePipelining = YES;
// 3.设置请求头部
if (sself.headersFilter) {
request.allHTTPHeaderFields = sself.headersFilter(url, [sself.HTTPHeaders copy]);
}
else {
request.allHTTPHeaderFields = sself.HTTPHeaders;
}
SDWebImageDownloaderOperation *operation = [[sself.operationClass alloc] initWithRequest:request inSession:sself.session options:options];
operation.shouldDecompressImages = sself.shouldDecompressImages;
if (sself.urlCredential) {
operation.credential = sself.urlCredential;
} else if (sself.username && sself.password) {
operation.credential = [NSURLCredential credentialWithUser:sself.username password:sself.password persistence:NSURLCredentialPersistenceForSession];
}
if (options & SDWebImageDownloaderHighPriority) {
operation.queuePriority = NSOperationQueuePriorityHigh;
} else if (options & SDWebImageDownloaderLowPriority) {
operation.queuePriority = NSOperationQueuePriorityLow;
}
[sself.downloadQueue addOperation:operation];
if (sself.executionOrder == SDWebImageDownloaderLIFOExecutionOrder) {//后进先出进行下载
// Emulate LIFO execution order by systematically adding new operations as last operation's dependency
[sself.lastAddedOperation addDependency:operation];
sself.lastAddedOperation = operation;
}
return operation;
}];
}
根据token取消operation
- (void)cancel:(nullable SDWebImageDownloadToken *)token {
dispatch_barrier_async(self.barrierQueue, ^{
SDWebImageDownloaderOperation *operation = self.URLOperations[token.url];
BOOL canceled = [operation cancel:token.downloadOperationCancelToken];
if (canceled) {
[self.URLOperations removeObjectForKey:token.url];
}
});
}
将任务添加到createCallback里,并且返回一个SDWebImageDownloadToken
- (nullable SDWebImageDownloadToken *)addProgressCallback:(SDWebImageDownloaderProgressBlock)progressBlock
completedBlock:(SDWebImageDownloaderCompletedBlock)completedBlock
forURL:(nullable NSURL *)url
createCallback:(SDWebImageDownloaderOperation *(^)(void))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 nil;
}
__block SDWebImageDownloadToken *token = nil;
//等待在它前面插入队列的任务先执行完,等待他们自己的任务执行完再执行后面的任务 1.dispatch_barrier_sync将自己的任务插入到队列的时候,需要等待自己的任务结束之后才会继续插入被写在它后面的任务,然后执行它们 2.dispatch_barrier_async将自己的任务插入到队列之后,不会等待自己的任务结束,它会继续把后面的任务插入到队列,然后等待自己的任务结束后才执行后面任务。
dispatch_barrier_sync(self.barrierQueue, ^{
SDWebImageDownloaderOperation *operation = self.URLOperations[url];
if (!operation) {
// 执行operationCallback回调的代码 :也就是去downloadImageWithURL 这个方法里生成operation
operation = createCallback();
self.URLOperations[url] = operation;
// 初始化SDWebImageDownloaderOperation
__weak SDWebImageDownloaderOperation *woperation = operation;
operation.completionBlock = ^{ //下载完成 删除 url
dispatch_barrier_sync(self.barrierQueue, ^{
SDWebImageDownloaderOperation *soperation = woperation;
if (!soperation) return;
if (self.URLOperations[url] == soperation) {
[self.URLOperations removeObjectForKey:url];
};
});
};
}
id downloadOperationCancelToken = [operation addHandlersForProgress:progressBlock completed:completedBlock]; //绑定callback
token = [SDWebImageDownloadToken new];
token.url = url;
token.downloadOperationCancelToken = downloadOperationCancelToken;
});
return token;
}
是否暂停和恢复和取消所有的下载
- (void)setSuspended:(BOOL)suspended {
self.downloadQueue.suspended = suspended;
}
- (void)cancelAllDownloads {
[self.downloadQueue cancelAllOperations];
}
NSURLSessionDataDelegate
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler {
// Identify the operation that runs this task and pass it the delegate method
SDWebImageDownloaderOperation *dataOperation = [self operationWithTask:dataTask];
[dataOperation URLSession:session dataTask:dataTask didReceiveResponse:response completionHandler:completionHandler];
}
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
// Identify the operation that runs this task and pass it the delegate method
SDWebImageDownloaderOperation *dataOperation = [self operationWithTask:dataTask];
[dataOperation URLSession:session dataTask:dataTask didReceiveData:data];
}
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
willCacheResponse:(NSCachedURLResponse *)proposedResponse
completionHandler:(void (^)(NSCachedURLResponse *cachedResponse))completionHandler {
// Identify the operation that runs this task and pass it the delegate method
SDWebImageDownloaderOperation *dataOperation = [self operationWithTask:dataTask];
[dataOperation URLSession:session dataTask:dataTask willCacheResponse:proposedResponse completionHandler:completionHandler];
}
#pragma mark NSURLSessionTaskDelegate
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
// Identify the operation that runs this task and pass it the delegate method
SDWebImageDownloaderOperation *dataOperation = [self operationWithTask:task];
[dataOperation URLSession:session task:task didCompleteWithError:error];
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler {
// Identify the operation that runs this task and pass it the delegate method
SDWebImageDownloaderOperation *dataOperation = [self operationWithTask:task];
if ([dataOperation respondsToSelector:@selector(URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:)]) {
[dataOperation URLSession:session task:task willPerformHTTPRedirection:response newRequest:request completionHandler:completionHandler];
} else {
completionHandler(request);
}
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler {
// Identify the operation that runs this task and pass it the delegate method
SDWebImageDownloaderOperation *dataOperation = [self operationWithTask:task];
[dataOperation URLSession:session task:task didReceiveChallenge:challenge completionHandler:completionHandler];
}
这样写的原因是为了和SDWebImageDownloaderOperation共有一个session。delegate设置为自己,也就是当使用这个会话请求数据,收到响应时,会调用SDWebImageDownloader.m中的代理方法,然后再调用SDWebImageDownloaderOperation中的代理方法处理事情。
+load方法要点
当类被引用进项目的时候就会执行load函数(在main函数开始执行之前),与这个类是否被用到无关,每个类的load函数只会自动调用一次.由于load函数是系统自动加载的,因此不需要再调用[super load],否则父类的load函数会多次执行。
1.当父类和子类都实现load函数时,父类的load方法执行顺序要优先于子类
2.当一个类未实现load方法时,不会调用父类load方法
3.类中的load方法执行顺序要优先于类别(Category)
4.当有多个类别(Category)都实现了load方法,这几个load方法都会执行,但执行顺序不确定(其执行顺序与类别在Compile Sources中出现的顺序一致)
5.当然当有多个不同的类的时候,每个类load 执行顺序与其在Compile Sources出现的顺序一致
load调用时机比较早,当load调用时,其他类可能还没加载完成,运行环境不安全.
load方法是线程安全的,它使用了锁,我们应该避免线程阻塞在load方法.
+initialize方法要点
initialize在类或者其子类的第一个方法被调用前调用。即使类文件被引用进项目,但是没有使用,initialize不会被调用。由于是系统自动调用,也不需要显式的调用父类的initialize,否则父类的initialize会被多次执行。假如这个类放到代码中,而这段代码并没有被执行,这个函数是不会被执行的。
1.父类的initialize方法会比子类先执行
2.当子类不实现initialize方法,会把父类的实现继承过来调用一遍。在此之前,父类的方法会被优先调用一次
3.当有多个Category都实现了initialize方法,会覆盖类中的方法,只执行一个(会执行Compile Sources 列表中最后一个Category 的initialize方法)
注意:
在initialize方法收到调用时,运行环境基本健全。
initialize内部也使用了锁,所以是线程安全的。但同时要避免阻塞线程,不要再使用锁