2.5版本2012年3月22日发布
整个2.5版本SDWebImage核心围绕block设计(引入了全新block技术)
1. 类结构新增了两个类
- MKAnnotationView+WebCache 大头针图片
//------------------------2.5版本更新-功能扩展------------------------
@interface MKAnnotationView (WebCache) <SDWebImageManagerDelegate>
- (void)setImageWithURL:(NSURL *)url;
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder;
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options;
//------------------------2.5版本更新-对block支持------------------------
//重点:加入block支持(SDWebImage从2.5版本开始加入block支持)
//方法重载
#if NS_BLOCKS_AVAILABLE
- (void)setImageWithURL:(NSURL *)url success:(void (^)(UIImage *image))success failure:(void (^)(NSError *error))failure;
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder success:(void (^)(UIImage *image))success failure:(void (^)(NSError *error))failure;
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options success:(void (^)(UIImage *image))success failure:(void (^)(NSError *error))failure;
#endif
//------------------------------end-----------------------------
- (void)cancelCurrentImageLoad;
@end
//------------------------------end-----------------------------
//----------------------------2.5版本更新-功能扩展---------------------------
@implementation MKAnnotationView (WebCache)
- (void)setImageWithURL:(NSURL *)url{
[self setImageWithURL:url placeholderImage:nil];
}
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder{
[self setImageWithURL:url placeholderImage:placeholder options:0];
}
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options{
SDWebImageManager *manager = [SDWebImageManager sharedManager];
//从队列中删除正在进行中的下载加载程序
[manager cancelForDelegate:self];
self.image = placeholder;
if (url){
[manager downloadWithURL:url delegate:self options:options];
}
}
#if NS_BLOCKS_AVAILABLE
- (void)setImageWithURL:(NSURL *)url success:(void (^)(UIImage *image))success failure:(void (^)(NSError *error))failure{
[self setImageWithURL:url placeholderImage:nil success:success failure:failure];
}
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder success:(void (^)(UIImage *image))success failure:(void (^)(NSError *error))failure{
[self setImageWithURL:url placeholderImage:placeholder options:0 success:success failure:failure];
}
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options success:(void (^)(UIImage *image))success failure:(void (^)(NSError *error))failure{
SDWebImageManager *manager = [SDWebImageManager sharedManager];
//从队列中删除正在进行中的下载加载程序
[manager cancelForDelegate:self];
self.image = placeholder;
if (url){
[manager downloadWithURL:url delegate:self options:options success:success failure:failure];
}
}
#endif
- (void)cancelCurrentImageLoad{
[[SDWebImageManager sharedManager] cancelForDelegate:self];
}
- (void)webImageManager:(SDWebImageManager *)imageManager didFinishWithImage:(UIImage *)image{
self.image = image;
}
@end
//------------------------------end-----------------------------
- SDWebImageDecoder 图片编码器
//-------------------2.5版本更新-新增功能-图片编码--------------------
@protocol SDWebImageDecoderDelegate;
@interface SDWebImageDecoder : NSObject{
NSOperationQueue *imageDecodingQueue;
}
+ (SDWebImageDecoder *)sharedImageDecoder;
- (void)decodeImage:(UIImage *)image withDelegate:(id <SDWebImageDecoderDelegate>)delegate userInfo:(NSDictionary *)info;
@end
@protocol SDWebImageDecoderDelegate <NSObject>
- (void)imageDecoder:(SDWebImageDecoder *)decoder didFinishDecodingImage:(UIImage *)image userInfo:(NSDictionary *)userInfo;
@end
@interface UIImage (ForceDecode)
+ (UIImage *)decodedImageWithImage:(UIImage *)image;
@end
//-----------------------------end-------------------------------
//-------------------2.5版本更新-新增功能-图片编码--------------------
#define DECOMPRESSED_IMAGE_KEY @"decompressedImage"
#define DECODE_INFO_KEY @"decodeInfo"
#define IMAGE_KEY @"image"
#define DELEGATE_KEY @"delegate"
#define USER_INFO_KEY @"userInfo"
@implementation SDWebImageDecoder
static SDWebImageDecoder *sharedInstance;
+ (SDWebImageDecoder *)sharedImageDecoder{
if (!sharedInstance){
sharedInstance = [[SDWebImageDecoder alloc] init];
}
return sharedInstance;
}
- (instancetype)init{
self = [super init];
if (self) {
imageDecodingQueue = [[NSOperationQueue alloc] init];
}
return self;
}
//通知主线程
- (void)notifyDelegateOnMainThreadWithInfo:(NSDictionary *)dict{
SDWIRetain(dict);
NSDictionary *decodeInfo = [dict objectForKey:DECODE_INFO_KEY];
UIImage *decodedImage = [dict objectForKey:DECOMPRESSED_IMAGE_KEY];
id <SDWebImageDecoderDelegate> delegate = [decodeInfo objectForKey:DELEGATE_KEY];
NSDictionary *userInfo = [decodeInfo objectForKey:USER_INFO_KEY];
[delegate imageDecoder:self didFinishDecodingImage:decodedImage userInfo:userInfo];
SDWIRelease(dict);
}
- (void)decodeImageWithInfo:(NSDictionary *)decodeInfo{
UIImage *image = [decodeInfo objectForKey:IMAGE_KEY];
UIImage *decompressedImage = [UIImage decodedImageWithImage:image];
if (!decompressedImage){
// If really have any error occurs, we use the original image at this moment
decompressedImage = image;
}
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
decompressedImage, DECOMPRESSED_IMAGE_KEY,
decodeInfo, DECODE_INFO_KEY, nil];
[self performSelectorOnMainThread:@selector(notifyDelegateOnMainThreadWithInfo:) withObject:dict waitUntilDone:NO];
}
- (void)decodeImage:(UIImage *)image withDelegate:(id<SDWebImageDecoderDelegate>)delegate userInfo:(NSDictionary *)info{
NSDictionary *decodeInfo = [NSDictionary dictionaryWithObjectsAndKeys:
image, IMAGE_KEY,
delegate, DELEGATE_KEY,
info, USER_INFO_KEY, nil];
NSOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(decodeImageWithInfo:) object:decodeInfo];
[imageDecodingQueue addOperation:operation];
SDWIRelease(operation);
}
- (void)dealloc{
SDWISafeRelease(imageDecodingQueue);
SDWISuperDealoc;
}
@end
@implementation UIImage (ForceDecode)
//核心实现
+ (UIImage *)decodedImageWithImage:(UIImage *)image{
CGImageRef imageRef = image.CGImage;
//创建RGB彩色颜色空间图片
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(NULL,
CGImageGetWidth(imageRef),
CGImageGetHeight(imageRef),
8,
// Just always return width * 4 will be enough
CGImageGetWidth(imageRef) * 4,
// System only supports RGB, set explicitly
colorSpace,
// Makes system don't need to do extra conversion when displayed.
kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little);
CGColorSpaceRelease(colorSpace);
if (!context) return nil;
CGRect rect = (CGRect){CGPointZero, CGImageGetWidth(imageRef), CGImageGetHeight(imageRef)};
CGContextDrawImage(context, rect, imageRef);
CGImageRef decompressedImageRef = CGBitmapContextCreateImage(context);
CGContextRelease(context);
UIImage *decompressedImage = [[UIImage alloc] initWithCGImage:decompressedImageRef];
CGImageRelease(decompressedImageRef);
return SDWIReturnAutoreleased(decompressedImage);
}
@end
//-----------------------------end-------------------------------
- SDWebImagePrefetcher 批量下载
/--------------------------2.5版本更新-批量下载---------------------------
@interface SDWebImagePrefetcher : NSObject <SDWebImageManagerDelegate>{
NSArray *_prefetchURLs;
NSUInteger _skippedCount;
NSUInteger _finishedCount;
NSUInteger _requestedCount;
NSTimeInterval _startedTime;
}
//同时预取的最大url数,默认为3
@property (nonatomic, assign) NSUInteger maxConcurrentDownloads;
+ (SDWebImagePrefetcher *)sharedImagePrefetcher;
//分配url列表,让SDWebImagePrefetcher对预取队列,目前一次下载一张图片
//然后跳过下载失败的图片,进入列表中的下一个图片
- (void)prefetchURLs:(NSArray *)urls;
//删除并取消排队列表
- (void)cancelPrefetching;
@end
//---------------------------------end--------------------------------
//--------------------------2.5版本更新-批量下载---------------------------
@interface SDWebImagePrefetcher ()
@property (nonatomic, retain) NSArray *prefetchURLs;
@end
@implementation SDWebImagePrefetcher
static SDWebImagePrefetcher *instance;
@synthesize prefetchURLs;
@synthesize maxConcurrentDownloads;
+ (SDWebImagePrefetcher *)sharedImagePrefetcher{
if (instance == nil){
instance = [[SDWebImagePrefetcher alloc] init];
instance.maxConcurrentDownloads = 3;
}
return instance;
}
- (void)startPrefetchingAtIndex:(NSUInteger)index withManager:(SDWebImageManager *)imageManager{
if (index >= [self.prefetchURLs count]) return;
_requestedCount++;
[imageManager downloadWithURL:[self.prefetchURLs objectAtIndex:index] delegate:self options:SDWebImageLowPriority];
}
- (void)reportStatus{
NSUInteger total = [self.prefetchURLs count];
NSLog(@"Finished prefetching (%lu successful, %lu skipped, timeElasped %.2f)", total - _skippedCount, (unsigned long)_skippedCount, CFAbsoluteTimeGetCurrent() - _startedTime);
}
- (void)prefetchURLs:(NSArray *)urls{
[self cancelPrefetching]; // Prevent duplicate prefetch request
_startedTime = CFAbsoluteTimeGetCurrent();
self.prefetchURLs = urls;
// Starts prefetching from the very first image on the list with the max allowed concurrency
int listCount = [self.prefetchURLs count];
SDWebImageManager *manager = [SDWebImageManager sharedManager];
for (int i = 0; i < self.maxConcurrentDownloads && _requestedCount < listCount; i++)
{
[self startPrefetchingAtIndex:i withManager:manager];
}
}
- (void)cancelPrefetching{
self.prefetchURLs = nil;
_skippedCount = 0;
_requestedCount = 0;
_finishedCount = 0;
[[SDWebImageManager sharedManager] cancelForDelegate:self];
}
#pragma mark SDWebImagePrefetcher (SDWebImageManagerDelegate)
- (void)webImageManager:(SDWebImageManager *)imageManager didFinishWithImage:(UIImage *)image{
_finishedCount++;
NSLog(@"Prefetched %d out of %d", _finishedCount, [self.prefetchURLs count]);
if ([self.prefetchURLs count] > _requestedCount){
[self startPrefetchingAtIndex:_requestedCount withManager:imageManager];
} else if (_finishedCount == _requestedCount){
[self reportStatus];
}
}
- (void)webImageManager:(SDWebImageManager *)imageManager didFailWithError:(NSError *)error{
_finishedCount++;
NSLog(@"Prefetched %d out of %d (Failed)", _finishedCount, [self.prefetchURLs count]);
// Add last failed
_skippedCount++;
if ([self.prefetchURLs count] > _requestedCount){
[self startPrefetchingAtIndex:_requestedCount withManager:imageManager];
} else if (_finishedCount == _requestedCount){
[self reportStatus];
}
}
- (void)dealloc{
self.prefetchURLs = nil;
SDWISuperDealoc;
}
@end
//---------------------------------end--------------------------------
2. SDWebImageManager
- 新增SDWebImageOptions 下载模式
- 新增缓存URL
- 新增下载方法重载
downloadWithURL
- 废弃了两个曾经使用bool类型方法重载,现在改为SDWebImageOptions方式
- 增加了下载重载方法block支持
NS_BLOCKS_AVAILABLE
//------------------2.5版本更新-图片选项----------------------
typedef enum{
//如果下载失败,还会继续尝试下载
SDWebImageRetryFailed = 1 << 0,
//滑动的时候Scrollview不下载,手从屏幕上移走,Scrollview开始减速的时候才会开始下载图片
SDWebImageLowPriority = 1 << 1,
//禁止磁盘缓存,只有内存缓存
SDWebImageCacheMemoryOnly = 1 << 2
} SDWebImageOptions;
//--------------------------end-----------------------------
@interface SDWebImageManager : NSObject <SDWebImageDownloaderDelegate, SDImageCacheDelegate>{
NSMutableArray *downloaders;
NSMutableDictionary *downloaderForURL;
NSMutableArray *failedURLs;
NSMutableArray *downloadDelegates;
NSMutableArray *cacheDelegates;
//------------------2.5版本更新-缓存URL----------------------
NSMutableArray *cacheURLs;
//--------------------------end-----------------------------
}
+ (id)sharedManager;
- (UIImage *)imageWithURL:(NSURL *)url;
- (void)downloadWithURL:(NSURL *)url delegate:(id<SDWebImageManagerDelegate>)delegate;
- (void)cancelForDelegate:(id<SDWebImageManagerDelegate>)delegate;
//------------------2.5版本更新-图片选项----------------------
- (void)downloadWithURL:(NSURL *)url delegate:(id<SDWebImageManagerDelegate>)delegate options:(SDWebImageOptions)options;
//--------------------------end-----------------------------
//--------------------------2.5版本更新-已经忽略(deprecated)---------------------------
//SDWebImageRetryFailed
- (void)downloadWithURL:(NSURL *)url delegate:(id<SDWebImageManagerDelegate>)delegate retryFailed:(BOOL)retryFailed __attribute__ ((deprecated));
//SDWebImageRetryFailed|SDWebImageLowPriority
- (void)downloadWithURL:(NSURL *)url delegate:(id<SDWebImageManagerDelegate>)delegate retryFailed:(BOOL)retryFailed lowPriority:(BOOL)lowPriority __attribute__ ((deprecated));
//---------------------------------------end-----------------------------------------
//--------------------------2.5版本更新-回调方法---------------------------
#if NS_BLOCKS_AVAILABLE
- (void)downloadWithURL:(NSURL *)url delegate:(id)delegate options:(SDWebImageOptions)options success:(void (^)(UIImage *image))success failure:(void (^)(NSError *error))failure;
#endif
//---------------------------------end-----------------------------------
@end
//-----------------------2.5版本更新-支持block-----------------------
#if NS_BLOCKS_AVAILABLE
typedef void(^SuccessBlock)(UIImage *image);
typedef void(^FailureBlock)(NSError *error);
@interface SDWebImageManager ()
@property (nonatomic, copy) SuccessBlock successBlock;
@property (nonatomic, copy) FailureBlock failureBlock;
@end
#endif
//------------------------------end--------------------------------
static SDWebImageManager *instance;
@implementation SDWebImageManager
//-----------------------2.5版本更新-支持block-----------------------
#if NS_BLOCKS_AVAILABLE
@synthesize successBlock;
@synthesize failureBlock;
#endif
//------------------------------end--------------------------------
//-----------------------2.5版本更新-优化-----------------------
- (void)downloadWithURL:(NSURL *)url delegate:(id<SDWebImageManagerDelegate>)delegate options:(SDWebImageOptions)options{
//非常常见的错误是使用NSString对象而不是NSURL发送URL。出于某种奇怪的原因,XCode不会这样做
//为这种类型不匹配抛出任何警告。在这里,我们通过允许url作为NSString传递来防止这个错误。
if ([url isKindOfClass:NSString.class]){
url = [NSURL URLWithString:(NSString *)url];
}
if (!url || !delegate || (!(options & SDWebImageRetryFailed) && [failedURLs containsObject:url])){
return;
}
//检查磁盘上的缓存异步,这样我们就不会阻塞主线程
[cacheDelegates addObject:delegate];
[cacheURLs addObject:url];
NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:delegate, @"delegate", url, @"url", [NSNumber numberWithInt:options], @"options", nil];
[[SDImageCache sharedImageCache] queryDiskCacheForKey:[url absoluteString] delegate:self userInfo:info];
}
//-------------------------------end-----------------------------
//-----------------------2.5版本更新-支持block-----------------------
#if NS_BLOCKS_AVAILABLE
- (void)downloadWithURL:(NSURL *)url delegate:(id)delegate options:(SDWebImageOptions)options success:(void (^)(UIImage *image))success failure:(void (^)(NSError *error))failure{
self.successBlock = success;
self.failureBlock = failure;
[self downloadWithURL:url delegate:delegate options:options];
}
#endif
//-------------------------------end-----------------------------
- (void)cancelForDelegate:(id<SDWebImageManagerDelegate>)delegate{
NSUInteger idx;
//-----------------------2.5版本更新-功能更新-----------------------
while ((idx = [cacheDelegates indexOfObjectIdenticalTo:delegate]) != NSNotFound){
[cacheDelegates removeObjectAtIndex:idx];
[cacheURLs removeObjectAtIndex:idx];
}
//----------------------------end-----------------------------
while ((idx = [downloadDelegates indexOfObjectIdenticalTo:delegate]) != NSNotFound){
SDWebImageDownloader *downloader = SDWIReturnRetained([downloaders objectAtIndex:idx]);
[downloadDelegates removeObjectAtIndex:idx];
[downloaders removeObjectAtIndex:idx];
if (![downloaders containsObject:downloader]){
//没有更多的委托在等待这个下载,取消它
[downloader cancel];
[downloaderForURL removeObjectForKey:downloader.url];
}
SDWIRelease(downloader);
}
}
//--------------------------2.5版本更新-优化--------------------------
- (NSUInteger)indexOfDelegate:(id<SDWebImageManagerDelegate>)delegate waitingForURL:(NSURL *)url{
//做一个线性搜索,简单(即使低效)
NSUInteger idx;
for (idx = 0; idx < [cacheDelegates count]; idx++){
if ([cacheDelegates objectAtIndex:idx] == delegate && [[cacheURLs objectAtIndex:idx] isEqual:url]){
return idx;
}
}
return NSNotFound;
}
//--------------------------------end--------------------------------
- (void)imageCache:(SDImageCache *)imageCache didFindImage:(UIImage *)image forKey:(NSString *)key userInfo:(NSDictionary *)info{
//--------------------------2.5版本更新-优化--------------------------
NSURL *url = [info objectForKey:@"url"];
//----------------------------end-----------------------------
id<SDWebImageManagerDelegate> delegate = [info objectForKey:@"delegate"];
NSUInteger idx = [self indexOfDelegate:delegate waitingForURL:url];
if (idx == NSNotFound){
//请求已被取消
return;
}
if ([delegate respondsToSelector:@selector(webImageManager:didFinishWithImage:)]){
[delegate performSelector:@selector(webImageManager:didFinishWithImage:) withObject:self withObject:image];
}
//--------------------------2.5版本更新-优化--------------------------
if ([delegate respondsToSelector:@selector(webImageManager:didFinishWithImage:forURL:)]){
objc_msgSend(delegate, @selector(webImageManager:didFinishWithImage:forURL:), self, image, url);
}
//支持block
#if NS_BLOCKS_AVAILABLE
if (self.successBlock){
self.successBlock(image);
}
#endif
//----------------------------end-----------------------------
[cacheDelegates removeObjectAtIndex:idx];
//--------------------------2.5版本更新-优化--------------------------
[cacheURLs removeObjectAtIndex:idx];
//----------------------------end-----------------------------
}
- (void)imageCache:(SDImageCache *)imageCache didNotFindImageForKey:(NSString *)key userInfo:(NSDictionary *)info{
NSURL *url = [info objectForKey:@"url"];
id<SDWebImageManagerDelegate> delegate = [info objectForKey:@"delegate"];
//------------------------2.5版本更新-优化----------------------
SDWebImageOptions options = [[info objectForKey:@"options"] intValue];
//----------------------------end-----------------------------
NSUInteger idx = [self indexOfDelegate:delegate waitingForURL:url];
if (idx == NSNotFound){
//请求已被取消
return;
}
[cacheDelegates removeObjectAtIndex:idx];
[cacheURLs removeObjectAtIndex:idx];
//为相同的URL共享相同的下载加载程序,所以我们不会多次下载相同的URL
SDWebImageDownloader *downloader = [downloaderForURL objectForKey:url];
//------------------------2.5版本更新-优化----------------------
if (!downloader){
downloader = [SDWebImageDownloader downloaderWithURL:url delegate:self userInfo:info lowPriority:(options & SDWebImageLowPriority)];
[downloaderForURL setObject:downloader forKey:url];
} else {
//重用共享下载器
downloader.userInfo = info;
downloader.lowPriority = (options & SDWebImageLowPriority);
}
//----------------------------end-----------------------------
[downloadDelegates addObject:delegate];
[downloaders addObject:downloader];
}
//--------------------------------下载器----------------------------------
//------------------------2.5版本更新-优化-新增block兼容--------------------
- (void)imageDownloader:(SDWebImageDownloader *)downloader didFinishWithImage:(UIImage *)image{
SDWIRetain(downloader);
SDWebImageOptions options = [[downloader.userInfo objectForKey:@"options"] intValue];
//用这个下载器通知所有下载delegate
for (NSInteger idx = (NSInteger)[downloaders count] - 1; idx >= 0; idx--){
NSUInteger uidx = (NSUInteger)idx;
SDWebImageDownloader *aDownloader = [downloaders objectAtIndex:uidx];
if (aDownloader == downloader){
id<SDWebImageManagerDelegate> delegate = [downloadDelegates objectAtIndex:uidx];
SDWIRetain(delegate);
SDWIAutorelease(delegate);
//---------------------2.5版本更新-优化-新增block兼容-------------------
if (image){
if ([delegate respondsToSelector:@selector(webImageManager:didFinishWithImage:)]){
[delegate performSelector:@selector(webImageManager:didFinishWithImage:) withObject:self withObject:image];
}
if ([delegate respondsToSelector:@selector(webImageManager:didFinishWithImage:forURL:)]){
objc_msgSend(delegate, @selector(webImageManager:didFinishWithImage:forURL:), self, image, downloader.url);
}
//NS_BLOCKS_AVAILABLE表示:Block是iOS在4.0之后新增的程序语法->程序兼容适配
#if NS_BLOCKS_AVAILABLE
if (self.successBlock){
self.successBlock(image);
}
#endif
} else {
if ([delegate respondsToSelector:@selector(webImageManager:didFailWithError:)]){
[delegate performSelector:@selector(webImageManager:didFailWithError:) withObject:self withObject:nil];
}
if ([delegate respondsToSelector:@selector(webImageManager:didFailWithError:forURL:)]){
objc_msgSend(delegate, @selector(webImageManager:didFailWithError:forURL:), self, nil, downloader.url);
}
#if NS_BLOCKS_AVAILABLE
if (self.failureBlock){
self.failureBlock(nil);
}
#endif
}
//--------------------------------end---------------------------
[downloaders removeObjectAtIndex:uidx];
[downloadDelegates removeObjectAtIndex:uidx];
}
}
if (image){
//将图像存储在缓存中
[[SDImageCache sharedImageCache] storeImage:image
imageData:downloader.imageData
forKey:[downloader.url absoluteString]
toDisk:!(options & SDWebImageCacheMemoryOnly)];
} else if (!(options & SDWebImageRetryFailed)){
//无法从这个URL下载图像,将URL标记为failed,这样我们就不会一次又一次地尝试失败
//(只有在SDWebImageRetryFailed未被激活时才这样做)
[failedURLs addObject:downloader.url];
}
//释放下载器
[downloaderForURL removeObjectForKey:downloader.url];
SDWIRelease(downloader);
}
- (void)imageDownloader:(SDWebImageDownloader *)downloader didFailWithError:(NSError *)error;{
SDWIRetain(downloader);
//用这个下载器通知所有下载delegate
for (NSInteger idx = (NSInteger)[downloaders count] - 1; idx >= 0; idx--){
NSUInteger uidx = (NSUInteger)idx;
SDWebImageDownloader *aDownloader = [downloaders objectAtIndex:uidx];
if (aDownloader == downloader){
id<SDWebImageManagerDelegate> delegate = [downloadDelegates objectAtIndex:uidx];
SDWIRetain(delegate);
SDWIAutorelease(delegate);
if ([delegate respondsToSelector:@selector(webImageManager:didFailWithError:)]){
[delegate performSelector:@selector(webImageManager:didFailWithError:) withObject:self withObject:error];
}
if ([delegate respondsToSelector:@selector(webImageManager:didFailWithError:forURL:)]){
objc_msgSend(delegate, @selector(webImageManager:didFailWithError:forURL:), self, error, downloader.url);
}
#if NS_BLOCKS_AVAILABLE
if (self.failureBlock){
self.failureBlock(error);
}
#endif
[downloaders removeObjectAtIndex:uidx];
[downloadDelegates removeObjectAtIndex:uidx];
}
}
// Release the downloader
[downloaderForURL removeObjectForKey:downloader.url];
SDWIRelease(downloader);
}
//------------------------------------end---------------------------------
@end
3. SDWebImageDownloader
- 下载器实现解码器代理
SDWebImageDecoderDelegate
- 新增下载失败回调
//-----------------------2.5版本更新-新增扩展->实现图片解码协议--------------
@interface SDWebImageDownloader (ImageDecoder) <SDWebImageDecoderDelegate>
@end
//---------------------------end-------------------------
//------------------------------2.5版本更新-新增回调-------------------------
- (void)connection:(NSURLConnection *)aConnection didReceiveResponse:(NSURLResponse *)response{
if ([((NSHTTPURLResponse *)response) statusCode] >= 400){
[aConnection cancel];
[[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStopNotification object:nil];
if ([delegate respondsToSelector:@selector(imageDownloader:didFailWithError:)]){
NSError *error = [[NSError alloc] initWithDomain:NSURLErrorDomain
code:[((NSHTTPURLResponse *)response) statusCode]
userInfo:nil];
[delegate performSelector:@selector(imageDownloader:didFailWithError:) withObject:self withObject:error];
}
self.connection = nil;
self.imageData = nil;
}
}
- (void)connectionDidFinishLoading:(NSURLConnection *)aConnection{
self.connection = nil;
[[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStopNotification object:nil];
if ([delegate respondsToSelector:@selector(imageDownloaderDidFinish:)]){
[delegate performSelector:@selector(imageDownloaderDidFinish:) withObject:self];
}
if ([delegate respondsToSelector:@selector(imageDownloader:didFinishWithImage:)]){
//------------------------------2.5版本更新-优化-------------------------
UIImage *image = SDScaledImageForPath(url.absoluteString, imageData);
[[SDWebImageDecoder sharedImageDecoder] decodeImage:image withDelegate:self userInfo:nil];
//---------------------------------end---------------------------------
}
}
//------------------------------2.5版本更新-优化-------------------------
- (void)imageDecoder:(SDWebImageDecoder *)decoder didFinishDecodingImage:(UIImage *)image userInfo:(NSDictionary *)userInfo{
[delegate performSelector:@selector(imageDownloader:didFinishWithImage:) withObject:self withObject:image];
}
//---------------------------------end----------------------------------
4. SDImageCache
- 系统版本兼容做了优化
>= __IPHONE_4_0
- 新增磁盘缓存大小功能
getSize
方法
- (instancetype)init{
self = [super init];
if (self) {
#if TARGET_OS_IPHONE
//订阅应用程序事件
//应用程序终止,里面回调didReceiveMemoryWarning方法,清空内存
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(clearMemory)
name:UIApplicationDidReceiveMemoryWarningNotification
object:nil];
//应用程序终止,里面回调willTerminate方法,清空磁盘
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(cleanDisk)
name:UIApplicationWillTerminateNotification
object:nil];
//-----------------------2.5版本更新-系统版本兼容->__IPHONE_OS_VERSION_MIN_REQUIRED-----------------------
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0
//--------------------------------end--------------------------------
UIDevice *device = [UIDevice currentDevice];
if ([device respondsToSelector:@selector(isMultitaskingSupported)] && device.multitaskingSupported){
//在后台时,清理内存以减少被杀死的机会
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(clearMemory)
name:UIApplicationDidEnterBackgroundNotification
object:nil];
}
#endif
#endif
}
return self;
}
//---------------2.5版本更新-新增功能--------------------
- (int)getSize;
//---------------------------end----------------------
5. SDWebImageCompat
- 平台兼容MRC处理
//-------------------2.5版本更新-MRC支持-------------------
#if ! __has_feature(objc_arc)
#define SDWIAutorelease(__v) ([__v autorelease]);
#define SDWIReturnAutoreleased SDWIAutorelease
#define SDWIRetain(__v) ([__v retain]);
#define SDWIReturnRetained SDWIRetain
#define SDWIRelease(__v) ([__v release]);
#define SDWISafeRelease(__v) ([__v release], __v = nil);
#define SDWISuperDealoc [super dealloc];
#define SDWIWeak
#else
// -fobjc-arc
#define SDWIAutorelease(__v)
#define SDWIReturnAutoreleased(__v) (__v)
#define SDWIRetain(__v)
#define SDWIReturnRetained(__v) (__v)
#define SDWIRelease(__v)
#define SDWISafeRelease(__v) (__v = nil);
#define SDWISuperDealoc
#define SDWIWeak __unsafe_unretained
#endif
//----------------------------end----------------------------
//-------------------2.5版本更新-图片尺寸-------------------
NS_INLINE UIImage *SDScaledImageForPath(NSString *path, NSData *imageData){
if (!imageData){
return nil;
}
UIImage *image = [[UIImage alloc] initWithData:imageData];
if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]){
CGFloat scale = 1.0;
if (path.length >= 8){
NSRange range = [path rangeOfString:@"@2x." options:0 range:NSMakeRange(path.length - 8, 5)];
if (range.location != NSNotFound){
scale = 2.0;
}
}
UIImage *scaledImage = [[UIImage alloc] initWithCGImage:image.CGImage scale:scale orientation:UIImageOrientationUp];
SDWISafeRelease(image)
image = scaledImage;
}
return SDWIReturnAutoreleased(image);
}
//----------------------------end----------------------------
网友评论