SDWebImage前世今生之V2.5版本

2.5版本2012年3月22日发布

整个2.5版本SDWebImage核心围绕block设计(引入了全新block技术)

1. 类结构新增了两个类

  • MKAnnotationView+WebCache 大头针图片
 //------------------------2.5版本更新-功能扩展------------------------
@interface MKAnnotationView (WebCache) 

- (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 )delegate userInfo:(NSDictionary *)info;

@end

@protocol SDWebImageDecoderDelegate 

- (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  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)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 {
    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 {
    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)delegate;
- (void)cancelForDelegate:(id)delegate;

//------------------2.5版本更新-图片选项----------------------
- (void)downloadWithURL:(NSURL *)url delegate:(id)delegate options:(SDWebImageOptions)options;
//--------------------------end-----------------------------

//--------------------------2.5版本更新-已经忽略(deprecated)---------------------------
//SDWebImageRetryFailed
- (void)downloadWithURL:(NSURL *)url delegate:(id)delegate retryFailed:(BOOL)retryFailed __attribute__ ((deprecated));
//SDWebImageRetryFailed|SDWebImageLowPriority
- (void)downloadWithURL:(NSURL *)url delegate:(id)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)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)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)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 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 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 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 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) 
@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----------------------------

你可能感兴趣的:(SDWebImage前世今生之V2.5版本)