美文网首页
SDWebImage前世今生之V2.5版本

SDWebImage前世今生之V2.5版本

作者: _相信自己_ | 来源:发表于2019-03-04 11:41 被阅读0次

    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----------------------------
    

    相关文章

      网友评论

          本文标题:SDWebImage前世今生之V2.5版本

          本文链接:https://www.haomeiwen.com/subject/wngduqtx.html