SDWebImage的探索(1)

来源:互联网 发布:手机网络挣钱 编辑:程序博客网 时间:2024/05/29 16:07

SDWebImage原理概括
1.NSCache+本地缓存
2.Operation和OperationQueue管理下载任务
3.通过监听器来更新控件图片
4.大量使用GCD加速代码执行

SDWebImageOperation

定义了一个SDWebImageOperation协议,协议仅定义了一个cancel的方法。

SDWebImageCompat

一个实现图片缩放的工具类。

  • 写了一个根据缓存的key是否包含『@3x』或『@2x』来把图片压缩到合适尺寸的方法,居然用了我今天才碰了壁的递归。。。支持动画。
  • 用到一个inline关键字来修饰一个方法。网上查到意思是表示内联函数。内联函数类似于宏定义,函数名类似于宏,在预编译的时候会在所有调用到这个函数的地方进行宏展开,省去了调用的开销,同时与宏定义不同的是,它是真正的函数,能够在执行时进行参数的有效性检查。
  • 用宏定义封装了两个方法:
#define dispatch_main_sync_safe(block)\    if ([NSThread isMainThread]) {\        block();\    } else {\        dispatch_sync(dispatch_get_main_queue(), block);\    }#define dispatch_main_async_safe(block)\    if ([NSThread isMainThread]) {\        block();\    } else {\        dispatch_async(dispatch_get_main_queue(), block);\    }

如果已经是主线程里面,调用dispatch_async的时候偶尔会crash,所以需要判断是否已经在主线程里面了。这是作用。

  • 里面用到了两种枚举类型NS_OPTIONS和NS_ENUM,实际上这两种类型本质上都是enum,他们只是在enum的基础上使用#define进行了封装。
    在使用时,
typedef NS_ENUM(NSInteger,enumName) {    a,    b};

意思是定义了枚举类型,存储类型是NSInteger,枚举值有两个,分别是a、b,并且为该枚举类型命别名为enumName。

typedef NS_OPTIONS(NSInteger, optionName){    Option1 = 0,    Option2= 1<<0 ,    Option3= 1<<1 ,};

意思是定义了枚举类型,存储类型是NSInteger,枚举值有两个,分别是Option1、Option2、Option3,并且为该枚举类型命别名为optionName。其中Option1存储值为0,Option2存储值为1,Option3存储值为1左移一位。

SDWebImageDownloader

这是一个异步下载器,负责新建下载任务,使用operation queue来管理下载任务,控制下载任务的执行顺序。

  • 定义了一个枚举类型SDWebImageDownloaderOptions,表示下载选项。
  • 为下载任务的开始,完成及取消分别定义了一个回调block。用一个字典callbacks将3个block存储起来。一个url对应一个或多个下载任务,因此一个url对应的callbacks字典会有一个或多个,因此用数组来存储同一个url的(可能多个)callbacks字典。然后再用一个总的字典URLCallbacks,来存储每一个url的回调block数组,key就是url。
  • 管理一个NSURLSession对象,实现了NSURLSession的代理方法,但是代理方法中实际上还是调用了在SDWebImageDownloaderOperation实现的NSURLSession的代理方法。
  • 提供了一个下载图片的方法:
    方法参数中包含上述的3个block。
    方法中主要完成下载任务的新建(SDWebImageDownloaderOperation)以及添加到operation queue。对同一个url的下载任务尚未完毕之前不会重复新建针对该url的下载任务。
    方法中将下载任务的3个回调block按照上述存储方式保存起来。并且在使用它们新建operation时进行了进一步的封装,主要是添加了执行block后将其移除的代码。

方法中使用NSMutableURLRequest来新建网络请求。通过自定义了的一个NS_OPTIONS类型SDWebImageDownloaderOptions来表示与下载相关的选项,包含与request相关的选项,从而简化了方法的参数。

方法中,新建operation使用了operation的初始化方法,方法参数包括3个回调block,NSURLSession对象,上面配置好的request,以及一个下载选项options,也就是说请求操作在operation内部完成。

方法中,对新建的operation的属性进行了设置,包括是否解压图片,优先级,证书等。然后将operation添加到operation queue。每次添加operation后会将这个operation保存为lastAddedOperation,以满足在下次准备添加operation的时候仍然可以获取当前队列的最后一个operation。这么做是为了控制queue的执行顺序的要求。默认情况下queue的执行顺序是FIFO,要求执行顺序是LIFO的情况下,在更新lastAddedOperation之前,把准备添加到队列的operation设置为lastAddedOperation的依赖即可。

  • 提供了一个暂停下载和取消所有下载的方法。
  • 为进度条SDNetworkActivityIndicator的使用写了一个初始化的类方法。

SDWebImageDownloaderOperation

一个NSOperation的子类,遵循协议。将一个下载任务封装成operation。

  • 继承NSOperation,遵循协议。定义了若干与request和url session有关的属性。
  • 用到了一个锁,表达如下:
-(void)method:(id)anObj{    @synchronized(anObj){        …    }}

这样,@synchronized大括号内部的代码,就被一个标识为anObj的锁锁住了。anObj是一个对象,这个对象是锁的唯一标识。一把锁中的内容,在同一时间只能被一个线程访问。也就是说,两个线程调用这个method:方法的时候,如果传入的参数是同一个对象,那么它们就不能够同时访问这段被synchronized锁住的代码,但是如果两个线程调用method:方法时传入的参数不是同一个对象,则它们遇到的是两个不同的锁,synchronized内的代码是可以被这两个线程同时访问的。这么看,其实这个@synchronized锁的作用和lock的区别在于,lock是锁住一段代码,而@synchronized是锁住一个对象,限制针对该对象的操作在同一时间只能被一个线程访问。

  • 定义了两个bool类型的值,finished和executing,分别用来替代NSOperation中定义的两个只读的属性isFinished和isExecuting。而且对这两个属性的setter方法中添加了对KVO的支持(细看有种偷龙转凤的感觉),如下:
- (void)setFinished:(BOOL)finished {    [self willChangeValueForKey:@"isFinished"];    _finished = finished;    [self didChangeValueForKey:@"isFinished"];}

<Foundation/NSKeyValueObserving.h>中为NSObject扩展了KVO的功能。其中有若干个willChangeValueForKey...didChangeValueForKey...方法。当willChangeValueForKey...被调用的瞬间,会捕捉这个key的value作为oldValue,当didChangeValueForKey...被调用的瞬间,会捕捉这个key的value作为newValue。这两个值就是监听者后面可以通过-observeValueForKeyPath:ofObject:change:context:中的change字典获取到的旧值和新值。
由于定义在NSObject,因此所有的类都继承了这些方法。

  • 用方法代替某些值,使得代码意义很明确
- (BOOL)shouldContinueWhenAppEntersBackground {    return self.options & SDWebImageDownloaderContinueInBackground;}
  • 这一段,在block外对self进行的弱引用的转换之后,在block内又进行的强引用的转换:
__weak __typeof__ (self) wself = self;self.backgroundTaskId = [app beginBackgroundTaskWithExpirationHandler:^{                __strong __typeof (wself) sself = wself;…

弱引用的转换是为了防止引用循环,强引用的转换是为了保证在block执行的时候要获取的对象不会被销毁。对此,这里给出了详细解释:http://blog.csdn.net/u013046795/article/details/50789442

  • 重写了NSOperation的start方法。使用session新建了dataTask并且resume。而且将当前的thread保存到了一个私有属性中,即self.thread。在重写cancel方法的时候,通过判断self.thread是否为空,就可以判断这个operation是否已经start了。
  • 在下载开始、停止、完成、以及session收到响应时发送通知,这里每次发送通知都会使用dispach_async方法,在主线程中发送。这是因为NSNotificationCenter只会把当前线程中post的通知广播在当前线程内进行广播。因此,需要能在主线程中接收到该通知的话,最方便的做法就是切换到主线程发送通知。
  • 实现了一个默认的session代理,也就是实现了和的协议方法。

在didReceiveResponse方法中,对response的statusCode进行判断,如果是304,表明图片未改变,可以直接返回缓存,所以直接取消下载任务。如果小于400又不等于304,就表明是请求成功,则继续执行。否则取消session的这个dataTask。

在didReceiveData方法中,拼接data到self.imageData(data是断续地到达的)。解析图片的长和宽以及方向(用到Core Graphics),并且保存起来。将图片转换成了bitmap,然后再转换成UIImage,然后对它进行了大小缩放,按需对它进行解压。最后调用了completedBlock将图片传出去。

在willCacheResponse方法中按需设置是否要对接收到的数据进行缓存。

在sessionTaskDidFinished方法中对接收到的完整数据self.imageData转换成UIImage,对它进行大小缩放,并且按需对它进行解压,调用completionBlock。

在didReceiveChallenge方法中提供了证书。

SDImageCache

管理图片的缓存。封装了若干方法,可以将图片数据缓存到内存或硬盘中。该类持有一个NSCache对象,用于将图片缓存到内存。持有默认的硬盘缓存路径,用于缓存图片到沙盒中。持有一些关于缓存方式的属性,比如是否缓存到内存,是否缓存到硬盘,最大缓存图片数,最大缓存空间,最大缓存像素等等。

  • 写了一个自动清除缓存的缓存类AutoPurgeCache,继承NSCache。其实就是在NSCache基础上添加了对UIApplicationDidReceiveMemoryWarningNotification的监听,当收到内存警告时调用NSCache的removeAllObjects方法。
  • 在SDImageCache的初始化方法,有两个参数,一个是缓存位置,一个是缓存的nameSpace,方法中创建了一个用于缓存图片的文件夹,文件夹位置按照参数,若没有指定则默认会在沙盒中,文件夹命名与nameSpace有关。方法中还创建了一个串行队列。方法中还给各种属性赋初值。并且添加了对UIApplicationDidReceiveMemoryWarningNotification、UIApplicationWillTerminateNotification、UIApplicationDidEnterBackgroundNotification的监听。
  • 提供了一个添加自定义的图片路径的方法。让SDWebImage帮忙管理本地图片。这个方法其实就是将一个路径加入到了数组。具体实现管理是在其他方法中实现的。
  • 写了一个私有方法,将指定的key转换成文件名,先对key进行md5加密,再拼接这个key的pathExtension(文件扩展名),获得文件名。另写了方法实现结合文件名生成文件路径。这是为了存储图片时为图片命名并生成缓存路径做准备的。
  • 提供了将指定图片缓存起来的方法。可以指定是否缓存到硬盘中。要为图片指定一个key。也就是用来生成文件名和缓存路径所使用的key。判断是否需要缓存到内存,如果需要就向本类持有的NSCache对象中插入该图片对象。如果需要缓存到硬盘中,首先要判断该图片是png还是jpg格式(所采用的策略是通过UIImage的透明度判断,如果有透明度就认为是png;在参数中imageData不为空时,判断data的前缀是否为特定值,如果符合就是png,不符合就是jpg),然后获取该图片的(png形式或jpg形式)的data,最后调用将data写入硬盘方法将data写入硬盘。
  • 写了一个将data写入硬盘的方法。主要是先判断缓存文件夹是否存在,不存在即创建,然后将data写入文件保存起来,文件路径用上面提到的方法实现。判断是否需要存储到iCloud,如果有需要就存储到iCloud。
  • 写了两个检查缓存中是否存在对应与某key的图片缓存,一个带有completionBlock,一个不带有。判断的时候,找出了对应该key的缓存路径——带有文件扩展名和不带有文件扩展名,对两个路径都进行了判断。
  • 写了一个从内存缓存中获取对应于某key的缓存图片。
  • 写了一个从硬盘缓存中获取对应于某key的缓存图片。在这个方法中,会首先判断这个key的缓存图片是否存在于内存缓存中,若存在就直接从内存缓存中取(速度快)。如果不存在于内存缓存中,就从硬盘缓存中取出缓存图片(写成了另一个方法)。还没完,虽然从硬盘缓存中找到了,但找到了说明该图片有可能会被再次使用,因此最好将它从硬盘缓存添加到内存缓存中,以便加速下次加载。因此接下来如果『是否缓存到内存』的属性为YES,就将图片添加到内存缓存中。
  • 写了上述的从硬盘缓存中取出缓存图片的方法。这个方法除了会对该类中定义的缓存文件夹路径进行查找,还会对自定义图片路径进行查找。最后对图片进行大小缩放,根据需要对图片进行解压。
  • 写了一个方法,将从硬盘缓存中获取对应于某key的缓存图片的一些列流程生成一个NSOperation对象。返回这个NSOperation对象。当图片可以直接从内存缓存中获取到的时候,会直接调用doneBlock(一个block类型参数),在doneBlock中传出图片,然后返回nil。
  • 写了几个删除缓存图片的方法,从硬盘或内存中删除指定key对应的缓存,或者删除全部。
  • 写了一个方法用于清除过期的缓存图片,并控制缓存总大小。在该方法中,访问了缓存文件的三个文件信息,分别是『是不是文件夹』、『修改日期』、『文件大小』。
    通过文件的url访问文件信息:
NSDictionary *resourceValues = [fileURL resourceValuesForKeys:resourceKeys error:NULL];

resourceValues字典中就包含了fileURL所指文件的文件信息,每项信息对应了一个key,比如,修改日期对应了NSURLContentModificationDateKey。通过key来从字典中提取出对应的文件信息。这个key值可以在<Foundation/NSURL.h>中找到。以上方法,第一个参数是数组,将需要的文件信息的key值添加到数组中,通过这种方法指定返回的字典中应包含哪些文件信息。

方法中,使用NSDirectoryEnumerator来遍历缓存文件夹中的所有缓存文件(不包括文件夹),先判断缓存文件的最新修改日期,如果早于限制日期,则添加到数组urlsToDelete中,然后继续循环。

判断两个日期的先后可以通过-(NSData *)laterDate:(NSData *)anotherDate;方法,该方法会返回两个日期中时间较后的日期。其实还有-earlierDate:返回较早的日期。

如果该文件的修改日期没有超期,那么将它的文件信息字典作为value,对应的url作为key,加入到字典cacheFiles中。还要判断该文件的占用大小,并将该文件大小加到记录总大小的量currentCacheSize中,便利结束后需要根据这个总大小是否超过最大内存限制来判断需不需要再删掉一些缓存文件。

currentCacheSize大于最大文件限制的情况下,删除一些缓存文件,使得缓存文件的总大小不大于currentCacheSize的一半。先对之前存好cacheFiles中的元素按照修改日期进行排序,当然是时间早的在前,时间新的在后。之后,开始遍历排好序的cacheFiles,一边遍历一边删除缓存文件,并检测currentCacheSize是否已经达到期望值,一旦达到就break。最后执行completionBlock。原因是这个类中的各个方法的completionBlock都是切换到主线程执行的,这个类通常是会在主线程中被创建和使用,自然completionBlock也应该切换回主线程中执行。

  • 写了一个在后台清理缓存的方法。这个方法实际上就是调用上面一个方法。关键是为该方法的执行争取了后台运行时间。通过以下方法争取后台运行时间:
__block UIBackgroundTaskIdentifier bgTask = [[UIApplication shareApplication] beginBackgroundTaskWithExpirationHandler:^{        [application endBackgroundTask:bgTask];        bgTask = UIBackgroundTaskInvalid;    }];

调用该方法会返回一个后台任务标识,也就是这里的bgTask。每一个后台任务标识在产生以后,都必须对应调用endBackgroundTask:方法,如这里的[[UIApplication shareApplication] endBackgroundTask:bgTask]。用这个方法来结束任务。另外还要将这个标识赋值为UIBackgroundTaskInvalid,声明这个任务结束了。当然,在做上述两步之前,还应该把该做的清理工作做完,比如结束线程,移除定时器等等。beginBackgroundTaskWithExpirationHandler方法还有一个参数ExpirationHandler,它表示所争取的后台时间用完时会调用的block。因此,不管任务是否完成,都需要在这个block中把该安置的工作做完。在调用了这个方法之后就可以去开始要做的任务了。通常在任务的最后,也会调用一次endBackgroundTask:方法,来主动结束任务,不必要等到争取的后台时间用完才被动结束。

  • 写了一个获取硬盘缓存总大小的方法,该方法通过遍历硬盘缓存文件夹下所有内容,并叠加文件大小来获得。在这个方法中,没有使用上面的resourceValuesForKeys:方法来获取文件大小,而是通过访问文件的attributes对象来获取:
NSDictionary *attrs = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil];size += [attrs fileSize];
  • 还写了计算硬盘缓存文件总数的方法。

SDWebImageManager

该类使用单例模式。结合SDWebImageDownloader和SDImageCache,实现了图片带缓存的下载功能。

  • 定义了表示图片选项的枚举类型SDWebImageOptions。定义了一个协议SDWebImageManagerDelegate。协议中有两个可选方法,一个是用于在缓存中不存在某图片时,控制是否需要下载某图片;另一个是用于将下载好的图片进行转换以便马上使用。
  • 定义了一个SDWebImageCombinedOperation类,这个类也遵循< SDWebImageOperation>协议,定义了一个cancelled属性,以及一个表示缓存操作的NSOperation类型的属性。之所以要定义这个类而不直接使用SDWebImageDownloaderOperation类来表示下载任务,有两个原因,第一是为了可以在下面使用中修改cancelled属性的值,在SDWebImageDownloaderOperation中cancelled属性对外是只读的;第二是因为一个操作表示一个获取图片的动作,通常优先从缓存中取出图片,缓存中没有才需要下载,而SDWebImageDounloaderOperation是专门用来下载的,没有包含查找缓存的功能。
  • 定义了一个block类型SDWebImageCacheKeyFilterBlock,用于在使用某url生成key之前,先把url的某些动态信息除掉,以便可以用简洁一点的url来生成key。因此这个block的内容就是对url的操作,返回值是一个简洁版的url。
  • 初始化方法中,会初始化一个缓存对象(SDImageCache),一个downloader(SDWebImageDownloader对象),一个NSMutableSet用于存储曾经请求失败的url(黑名单),一个NSMutableArray(runningOperations)用于存储正在执行的下载任务(SDWebImageDownloaderOperation对象)。
  • 一个用url生成key的方法,这个key将会用来缓存用url下载到的图片。这个方法就用到了上述的SDWebImageCacheKeyFilterBlock。
  • 写了一系列询问缓存中是否存在某图片的方法,思路都是先生成某url的key,然后用这个key,调用SDImageCache对象的方法获得查询结果。
  • 写了一个获取图片的方法,参数包括url,图片选项option,一个表示进度的progressBlock,一个表示完成回调的completedBlock。获取图片的执行思路就是先启动一个操作是获取缓存图片的,然后在该操作的回调方法中判断是否获取到图片,在获取不到图片的情况下启动下载任务。

该方法中,为了弥补一个大家都容易犯的错误,也就是容易在NSURL类型的参数中传入NSString类型的url,这里做了一步工作就是把NSString转换成NSURL(良苦用心哦)。另外在使用这个url之前,还是继续对url的类型进行了判断,这次是为了防止app因为参数类型错误而崩溃(谨慎的很)。

方法中,先判断该url是否存在于黑名单中,如果存在,而且下载选项里有设置为不尝试连接失败url的话,就直接返回。在调用- (BOOL)containsObject:(ObjectType)anObject;的时候很谨慎地使用@synchronized锁住。

方法中,如果url不存在于黑名单,会将新建的SDWebImageCombinedOperation对象插入到runningOperations中,这个对象就是获取图片任务。然后,调用SDImageCache对象的方法,由SDWebImageCombinedOperation对象持有这个方法返回的缓存任务。在方法的回调block中获取图片,在处理图片之前先检查了SDWebImageCombinedOperation对象是否被取消了,如果取消就将它从runningOperations中移除并返回,如果没取消就对获取到的图片进行判断和处理。

如果缓存图片不为空,就通过completedBlock把图片传出去,然后将该获取图片任务从runningOperations中移除。

如果缓存图片为空,但是本类的代理拒绝了对本url的下载,那么调用completedBlock,返回结果,然后同样将该获取图片任务从runningOperations中移除。

如果缓存图片为空,或者下载选项中设置了需要刷新图片缓存的情况下,就要进行图片的下载。还有一种需要下载图片的情况是,本类的代理实现了判断对应某个url是否应该下载图片的方法,而且该方法返回YES。接下来对于需要刷新图片缓存的情况下,会直接调用completeBlock把图片传出去,但是因为要刷新缓存,所以不会马上返回,会继续下面的下载动作。

在开始下载之前,需要对图片选项进行解析。由于下载需要用到SDWebImageDownloader,而在SDWebImageDownloader中,影响下载的选项是SDWebImageDownloaderOptions,而在本类中,是用SDWebImageOptions表示图片选项的。因此要根据SDWebImageOptions和SDWebImageDownloaderOptions的对应关系,构造一个意义与option(上面提到的SDWebImageDownloader类型参数)等价的SDWebImageDownloaderOptions。这里面,枚举类型使用的是NS_OPTION,枚举值之间都是位移的关系。于是乎可以通过按位或操作 | 实现枚举值的多选。相反,要从一个NS_OPTION变量中取消某个枚举值,可以通过按位与这个枚举值的负值(准确来说应该是按位取反以后的值,不应该说负值),比如:

downloaderOptions &= ~SDWebImageDownloaderProgressiveDownload;

然后就是调用SDWebImageDownloader提供的下载图片的方法来下载图片,在加载完成的回调block中,对下载结果进行处理。首先,判断下载任务是否已经被取消了,如果没有才继续(可以发现,每次在开始一个新的数据操作之前,都会加入对操作是否取消的判断,这么做加强了一个复杂操作的可控性,保证了取消操作的有效性,即数据未被改变)。然后下载是否有错误,若有错误(排除由设备当前状态导致的错误)就把这个url加入黑名单。如果发生的错误与当前设备状况有关,而且options中设置了重新尝试下载失败的url,就再把这个url从黑名单中移除。

如果没有错误,而且这个回调block的参数finished为YES的情况下,就会考虑将图片加入self.imageCache中。当然在此之前需要可选地对图片进行处理,需要处理的情况为,options中指定了要处理动图,或者这个图片本身就是动图。处理动图用到本类的代理的代理方法,如果代理方法未实现,也不会处理图片。处理完图片以后,又再次判断下载操作是否被取消了,如果没有的话就把图片缓存到self.imageCache中 。至此完成了图片下载操作,但仍需进行一下清理。也就是在finished为YES的情况下,整个获取图片的任务已完成,因此要把这个任务从runningOperations中移除,那么下载图片方法的回调函数已经写完。

上面每次对数据进行操作之前都会判断整个获取图片的操作是否已取消。只有在操作未取消的情况下(SDWebImageCombinedOperation对象的cancelled属性为NO)才会继续操作,否则就会立刻退出,这样保证了取消操作的即时性。但是在下载任务开始到调用下载完成的回调方法之间,并不能添加对这个cancelled属性的判断,因此如果SDWebImageCombinedOperation对象的cancel方法中仅仅是把cancelled属性置为YES,是无法保证取消操作对于下载任务的即时性的。解决的办法是在SDWebImageCombinedOperation对象的cancel方法中,除了把cancelled属性置为YES,还通过调用下载任务(SDWebImageDownloaderOperation对象)的cancel方法来把下载任务取消掉,就可以解决这个问题。由于下载任务是个局部变量,因此需要在这个获取图片方法内把取消操作封装成一个cancelBlock,之后在SDWebImageCombinedOperation类的cancel方法中调用这个cancelBlock即可。
最后该方法返回了表示获取图片任务的SDWebImageCombinedOperation对象。

  • 写了一个取消所有获取图片任务的方法。该方法中,先使runningOperations中所有的operation调用cancel方法。然后再清除runningOperations中的所有元素。这里在cancel所有operation的时候,并没有直接遍历runningOperation,而是先复制了一份保存到了数组copiedOperations中,然后再遍历copiedOperations来取消其中的operation。这么做非常安全,可以防止由于operation的取消操作没有在runningOperations释放完所有的operation之前完成所触发的crash。
  • 写了一个方法返回本SDWebImageManager当前是否在工作。判断准则在于runningOperations数组的元素个数是否大于零。

SDWebImageDecoder

解压器,其实就写了一个解压图片的方法。该方法通过使用CGBitmapContext重新绘制图片,来获得未压缩的图片。有关PNG的压缩和解压的原理和实现可以参照这个博客:http://blog.csdn.net/zykun/article/details/1825086

SDWebImagePrefetcher

该类是一个单例类,实现的功能是预先为一组url准备图片(存在内存中以便之后使用)。

  • 该类使用代理模式(也提供了对应的block方式)。定义了一个协议,这个协议中定义了两个方法,分别会在完成一张图片的准备时,和完成所有图片的准备时调用。该类中还有一个SDWebImageManager对象,当然会有一个代理。另外持有一个dispatch queue(默认是主线程队列)来处理准备图像的任务,还定义了一个表示最大并行下载量的属性,以及表示图片选项的SDWebImageOptions类型属性。这里提供的最大并行下载量的属性,实际上在使用点语法访问时,获取或设置的真正对象是SDWebImageManager.imageDownloader.maxConcurrentDownloads,也就是完成下载任务的NSOperationQueue对象的maxConcurrentOperationCount。
  • 定义了一个私有方法,从第index个url开始准备图片的方法。方法中使用SDWebImageManager来下载图片。方法中区分了已发起处理的url,处理完毕url的数量,处理成功的数量,处理失败的数量。使用了递归的思想,每次调用SDWebImageManager的下载图片方法就会让已发起处理的url的数量加一,通过判断已发起处理的url的数量是否超过url总数来决定是否再次自我调用,此时应该从第index+1个url开始。每次从SDWebImageManager的下载图片方法中返回,都会让处理完毕的url数量加一,并根据处理结果,让处理成功或处理失败的url数量加一。如果已处理完毕的url数量与已发起处理url的数量达到相等,就调用表示处理完毕的代理方法,以及调用表示完成的block,调用完以后马上设成nil。
  • 定义了一个开使准备图片的方法。这里为了提高准备图片的速度,发挥并行的性能,会多次调用上述从第index个url开始准备图片的方法。调用次数的上限是最大并行下载量或者待处理的url总数。
  • 定义了一个取消准备图像的方法。将所有量置0,然后调用SDWebImageManager对象的cancelAll方法。
0 0