




已阅读5页,还剩8页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
SDWebImage源码解读之SDWebImageDownloaderSDWebImageDownloader这个类非常简单,作者的设计思路也很清晰,但是我想在这说点题外话。如果有人问你:你怎么看待编程这件事?你怎么回答。这个问题是我在看这个类的时候,忽然出现在我脑子中的。我突然意识到,其实不管是函数还是属性,他们都是数据。我们编写的所有程序都是在处理数据。函数本身也是一种特殊的数据。真正难的是生产数据的这一过程。举个例子,给你一堆菜籽,要求生产出油来。怎么办?我们首先为这个任务设计一个函数:- (油)用菜籽生产油(菜籽);这就是我们最外层的函数,也应该是我们最开始想到的函数。然后经过我们的研究发现,这个生产过程很复杂,必须分工合作才能实现。于是我们把这个任务分割为好几个小任务:1. - (干净的菜籽)取出杂质(菜籽);2. - (炒熟的菜籽)把菜籽炒一下(干净的菜籽);3. - (蒸了的菜籽)把菜籽蒸一下(炒熟的菜籽);4. - (捆好的菜籽)把菜籽包捆成一块(蒸了的菜籽);5. - (油)撞击菜籽包(捆好的菜籽);大家有没有发现,整个榨油的过程就是对数据的处理。这一点其实很重要。如果没有把- (油)用菜籽生产油(菜籽);这一任务进行拆分,我们就会写出复杂无比的函数。那么就有人要问了,只要实现这个功能就行了呗。其实这往往是写不出好代码的原因。整个任务的设计应该是事先就设计好的。任务被分割成更小更简单的部分,然后再去实现这些最小的任务,不应该是编写边分割任务,往往临时分割的任务(也算是私有函数吧)没有最正确的界限。有了上边合理的分工之后呢,我们就可以进行任务安排了。我们回到现实开发中来。上边5个子任务的难度是不同的。有的人可能基础比较差,那么让他去干筛菜籽这种体力活,应该没问题。那些炒或者蒸的子任务是要掌握火候的,也就是说有点技术含量。那么就交给能胜任这项工作的人去做。所有的这一切,我们只要事先定义好各自的生产结果就行了,完全不影响每个程序的执行。怎么样?大家体会到这种编程设计的好处了吗?我还可以进行合并,把炒和煮合成一个小组,完全可行啊。好了这方面的思考就说这么多吧。如果我想买煮熟了的菜籽,是不是也很简单?有的人用原始的撞击菜籽包榨油,有的人却用最先进的仪器榨油,这就是编程技术和知识深度的区别啊。SDWebImageDownloaderOptions言归正传,当我们需要给某个功能添加Options的时候,一般使用枚举来实现。我们先看看支持的选项:typedef NS_OPTIONS(NSUInteger, SDWebImageDownloaderOptions) SDWebImageDownloaderLowPriority = 1 0, SDWebImageDownloaderProgressiveDownload = 1 1, / 带有进度 SDWebImageDownloaderUseNSURLCache = 1 2, / 使用URLCache SDWebImageDownloaderIgnoreCachedResponse = 1 3, / 不缓存响应 SDWebImageDownloaderContinueInBackground = 1 4, / 支持后台下载 SDWebImageDownloaderHandleCookies = 1 5, / 使用Cookies SDWebImageDownloaderAllowInvalidSSLCertificates = 1 6, / 允许验证SSL SDWebImageDownloaderHighPriority = 1 7, / 高权限 SDWebImageDownloaderScaleDownLargeImages = 1 8, / 裁剪大图片;这里提供了这么几种不同的选项,大家可以根据自己的需求选个合适的选项。这里作者使用了掩码。比如说,1 1 ,表示把1左移一位,我们把1携程二进制为:00000001,那么左移一位后就是:00000010 转成10进制后就是2,也就是说左移一位表示在原来的值上乘以2。再举个例子,当判断self.option是否是SDWebImageDownloaderIgnoreCachedResponse选项时,应该这么判断:self.option & SDWebImageDownloaderIgnoreCachedResponseSDWebImageDownloaderExecutionOrderSDWebImageDownloaderExecutionOrder定义了数据被调用的顺序。按照一般的想法。下载应该按照数据放入队列的顺序依次进行,但也支持后进先出这种方式。一个下载管理器应该这样管理下载,肯定有一个下载列表,我们可以假定这个列表保存在一个数组中,正常情况下我们应该每次取出数组中第1个元素来下载,这就是FIFO(先进先出)。那么我们要改为LIFO(后进先出),应该是针对某一个下载的,不应该是把取出数据的顺序改为从数组的最后一个元素取出。typedef NS_ENUM(NSInteger, SDWebImageDownloaderExecutionOrder) /* * Default value. All download operations will execute in queue style (first-in-first-out). */ SDWebImageDownloaderFIFOExecutionOrder, /* * All download operations will execute in stack style (last-in-first-out). */ SDWebImageDownloaderLIFOExecutionOrder;但是我有一个疑问,如果我只是想暂停某一个下载,我该怎么办呢?如果直接取消,那么点击继续的时候,要重新开启下载,肯定影响体验。这一点跟使用数组管理任务有点不同。辅助部分extern NSString * _Nonnull const SDWebImageDownloadStartNotification;extern NSString * _Nonnull const SDWebImageDownloadStopNotification;通过extern,我们就能够使用其他文件的代码。typedef void(SDWebImageDownloaderProgressBlock)(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL);typedef void(SDWebImageDownloaderCompletedBlock)(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished);命名Blocktypedef NSDictionary SDHTTPHeadersDictionary;typedef NSMutableDictionary SDHTTPHeadersMutableDictionary;命名字典typedef SDHTTPHeadersDictionary * _Nullable (SDWebImageDownloaderHeadersFilterBlock)(NSURL * _Nullable url, SDHTTPHeadersDictionary * _Nullable headers);这个block允许我们自定义请求头,通过Block传值,有一定的优点,我们可以拿到一些参数,然后在加工成我们需要的数据,最后返回。SDWebImageDownloadTokenSDWebImageDownloadToken作为每一个下载的唯一身份标识,SDWebImageDownloader和我们平时开发中的下载还是又不一样的地方的,它弱化了下载过程,比较强调的是下载结果。不支持断点下载(当然这可能没有必要)。如果我们需要设计一个自己的下载管理者,我们就应该设计一个类似SDWebImageDownloadToken这样的下载对象封装类,我需要的所有信息,都能在这个对象中获取,大家如果有兴趣,可以看看MCDownloadManager./* * A token associated with each download. Can be used to cancel a download */interface SDWebImageDownloadToken : NSObjectproperty (nonatomic, strong, nullable) NSURL *url;property (nonatomic, strong, nullable) id downloadOperationCancelToken;endSDWebImageDownloader.h/* * 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. */property (assign, nonatomic) NSTimeInterval downloadTimeout;/* * 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. */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 */- (nonnull instancetype)initWithSessionConfiguration:(nullable NSURLSessionConfiguration *)sessionConfiguration NS_DESIGNATED_INITIALIZER;我们都知道: 一个NSURLSession会话,使用NSURLSessionConfiguration进行配置,利用这一点,我们在设计自己的网络框架的时候,可以参考NSURLSessionConfiguration。暴露少量的属性来配置网络请求,后期维护起来也比较容易。使用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. */- (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. */- (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. */- (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 isnt 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 */- (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. */- (void)cancel:(nullable SDWebImageDownloadToken *)token;/* * Sets the download queue suspension state */- (void)setSuspended:(BOOL)suspended;/* * Cancels all download operations in the queue */- (void)cancelAllDownloads;SDWebImageDownloader.mproperty (strong, nonatomic, nonnull) NSOperationQueue *downloadQueue;property (weak, nonatomic, nullable) NSOperation *lastAddedOperation;property (assign, nonatomic, nullable) Class operationClass;property (strong, nonatomic, nonnull) NSMutableDictionary *URLOperations;property (strong, nonatomic, nullable) SDHTTPHeadersMutableDictionary *HTTPHeaders;/ This queue is used to serialize the handling of the network responses of all the download operation in a single queueproperty (SDDispatchQueueSetterSementics, nonatomic, nullable) dispatch_queue_t barrierQueue;/ The session in which data tasks will runproperty (strong, nonatomic) NSURLSession *session;这些属性可以说都是为了完成管理下载任务而存在的。downloadQueue 队列lastAddedOperation 用于记录最后添加的操作operationClass 支持我们自定义的操作类URLOperations 存放着所有的operationHTTPHeaders HTTP请求头barrierQueuesessioninitializeinitialize 和 load 这两个方法比较特殊,我们通过下边这个表格来看看他们的区别.+(void)load+(void)initialize执行时机在程序运行后立即执行在类的方法第一次被调时执行若自身未定义,是否沿用父类的方法?否是类别中的定义全都执行,但后于类中的方法覆盖类中的方法,只执行一个 + (void)initialize / Bind SDNetworkActivityIndicator if available (download it here: /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; 上边的方法是为了给图片下载绑定一个SDNetworkActivityIndicator,只有当这个SDNetworkActivityIndicator文件存在的情况下才会执行,目的就是当下在图片是,状态栏会转小菊花。初始化实现- (nonnull instancetype)initWithSessionConfiguration:(nullable NSURLSessionConfiguration *)sessionConfiguration if (self = super init) _operationClass = SDWebImageDownloaderOperation class; _shouldDecompressImages = YES; _executionOrder = SDWebImageDownloaderFIFOExecutionOrder; _downloadQueue = NSOperationQueue new; _downloadQueue.maxConcurrentOperationCount = 6; _downloadQ = 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; sessionConfiguration.timeoutIntervalForRequest = _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. */ self.session = NSURLSession sessionWithConfiguration:sessionConfiguration delegate:self delegateQueue:nil; return self;这里边做了必要的初始化,默认最大支持的并发数为6个,也就是说可以同时下载6张图片。*我们看看image/webp,image/*;q=0.8是什么意思,image/webp是web格式的图片,q=0.8指的是权重系数为0.8,q的取值范围是0 - 1, 默认值为1,q作用于它前边分号;前边的内容。在这里,image/webp,image/*;q=0.8表示优先接受image/webp,其次接受image/*的图片。set或者get方法- (void)setValue:(nullable NSString *)value forHTTPHeaderField:(nullable NSString *)field if (value) self.HTTPHeadersfield = value; else self.HTTPHeaders removeObjectForKey:field; - (nullable NSString *)valueForHTTPHeaderField:(nullable NSString *)field return self.HTTPHeadersfield;- (void)setMaxConcurrentDownloads:(NSInteger)maxConcurrentDownloads _downloadQueue.maxConcurrentOperationCount = maxConcurrentDownloads;- (NSUInteger)currentDownloadCount return _downloadQueue.operationCount;- (NSInteger)maxConcurrentDownloads return _downloadQueue.maxConcurrentOperationCount;- (void)setOperationClass:(nullable Class)operationClass if (operationClass & operationClass isSubclassOfClass:NSOperation class & operationClass conformsToProtocol:protocol(SDWebImageDownloaderOperationInterface) _operationClass = operationClass; else _operationClass = SDWebImageDownloaderOperation class; 为每个URL绑定事件- (nullable SDWebImageDownloadToken *)addProgressCallback:(SDWebImageDownloaderProgressBlock)progressBlock completedBlock:(SDWebImageDownloaderCompletedBlock)completedBlock forURL:(nullable NSURL *)url createCallback:(SDWebImageDownloaderOperation *()()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; dispatch_barrier_sync(self.barrierQueue, SDWebImageDownloaderOperation *operation = self.URLOperationsurl; if (!operation) operation = createCallback(); self.URLOperationsurl = operation; _weak SDWebImageDownloaderOperation *woperation = operation; pletionBlock = SDWebImageDownloaderOperation *soperation = woperation; if (!soperation) return; if (self.URLOperationsurl = soperation) self.URLOperations removeObjectForKey:url; ; ; id downloadOperationCancelToken = operation addHandlersForProgress:progressBlock completed:completedBlock; token = SDWebImageDownloadToken new; token.url = url; token.downloadOperationCancelToken = downloadOperationCancelToken; ); return token;每一个URL都会被作为每个下载的唯一标识,每一个下载都会绑定一个progressBlock和completeBlock,最终我们还要使用这个URL跟NSOperation建立联系。关于如何创建SDWebImageDownloaderOperation这一段代码,我采用注释的方式,大家看注释就行了。- (nullable SDWebImageDownloadToken *)downloadImageWithURL:(nullable NSURL *)url options:(SDWebImageDownloaderOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock _weak SDWebImageDownloader *wself = self; return self addProgressCallback:progressBlock completedBlock:completedBlock forURL:url createCallback:SDWebImageDownloaderOperation * _strong _typeof (wself) sself = wself; / 1.设置超时时间 NSTimeInterval timeoutInterval =
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 经皮肺穿刺患者介入术后护理
- 高血压年轻化护理
- 海运公司年终总结
- 《给矛树》课件教学课件
- 电动机的结构讲解
- 公司法学课件
- 项目财务尽调工作总结
- 政教处月度工作总结
- 2025标准苗木购销合同范本
- 公司招投标业务安全培训课件
- 初中作文指导-景物描写(课件)
- 植物灰分的测定
- 实验室资质认证评审准则最新版本课件
- 浦发银行个人信用报告异议申请表
- 《横》书法教学课件
- 文件外发申请单
- 历史选择性必修1 国家制度与社会治理(思考点学思之窗问题探究)参考答案
- 中国医院质量安全管理 第2-29部分:患者服务临床营养 T∕CHAS 10-2-29-2020
- 人大附小诗词选修课:苏轼生平
- 回转支承选型计算
- 特色小吃加盟合同书
评论
0/150
提交评论