美文网首页
研究一下开源框架SDWebImage

研究一下开源框架SDWebImage

作者: 克鲁德李 | 来源:发表于2016-07-27 16:17 被阅读0次

    1、首先他是通过UIImageView的类别来设计的 UIImageView (WebCache)
    在.m文件中最终都调用了这个方法进行图片网络请求:

    - (id <SDWebImageOperation>)downloadImageWithURL:(NSURL *)url
                                             options:(SDWebImageOptions)options
                                            progress:(SDWebImageDownloaderProgressBlock)progressBlock
                                           completed:(SDWebImageCompletionWithFinishedBlock)completedBlock
    

    注:这个方法是在这个类中SDWebImageManager.sharedManager,通过这种方式,这个类应该是单例类:

    @implementation SDWebImageManager
    
    + (id)sharedManager {
        static dispatch_once_t once;
        static id instance;
        dispatch_once(&once, ^{
            instance = [self new];
        });
        return instance;
    }
    

    这个方法足足写了140行代码:下面一步一步分析;

    a、首先会初始化一个队列SDWebImageCombinedOperation,从缓存中获取图片代码如下:

    - (NSOperation *)queryDiskCacheForKey:(NSString *)key done:(SDWebImageQueryCompletedBlock)doneBlock;
    

    在上面方法体里判断如果缓存里边有图片则通过block返回:

    if (image && options & SDWebImageRefreshCached) {
                    dispatch_main_sync_safe(^{
                        // If image was found in the cache bug SDWebImageRefreshCached is provided, notify about the cached image
                        // AND try to re-download it in order to let a chance to NSURLCache to refresh it from server.
                        completedBlock(image, nil, cacheType, YES, url);
                    });
                }
    

    b、否则就往下执行,通过下面这个方法获取网络图片

    - (id <SDWebImageOperation>)downloadImageWithURL:(NSURL *)url options:(SDWebImageDownloaderOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageDownloaderCompletedBlock)completedBlock;
    

    b1、下面就进入上面的方法中分析如何实现网络下载图片:
    在这个SDWebImageDownloader单例类中,又调用

    SDWebImageDownloaderOperation类中的
    - (id)initWithRequest:(NSURLRequest *)request
                  options:(SDWebImageDownloaderOptions)options
                 progress:(SDWebImageDownloaderProgressBlock)progressBlock
                completed:(SDWebImageDownloaderCompletedBlock)completedBlock
                cancelled:(SDWebImageNoParamsBlock)cancelBlock
    

    这个方法进行网络请求参数的初始化,由最后的NSURLConnection进行网络请求,最后在请求回来的block方法里边把返回回来的image返回并且进行缓存:

    completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) {
                                                                SDWebImageDownloader *sself = wself;
                                                                if (!sself) return;
                                                                __block NSArray *callbacksForURL;
                                                                dispatch_barrier_sync(sself.barrierQueue, ^{
                                                                    callbacksForURL = [sself.URLCallbacks[url] copy];
                                                                    if (finished) {
                                                                        [sself.URLCallbacks removeObjectForKey:url];
                                                                    }
                                                                });
                                                                for (NSDictionary *callbacks in callbacksForURL) {
                                                                    SDWebImageDownloaderCompletedBlock callback = callbacks[kCompletedCallbackKey];
                                                                    if (callback) callback(image, data, error, finished);
                                                                }
                                                            }
    

    这个是缓存方法:

    - (void)storeImage:(UIImage *)image recalculateFromImage:(BOOL)recalculate imageData:(NSData *)imageData forKey:(NSString *)key toDisk:(BOOL)toDisk {
        if (!image || !key) {
            return;
        }
        // if memory cache is enabled
        if (self.shouldCacheImagesInMemory) {
            NSUInteger cost = SDCacheCostForImage(image);
            [self.memCache setObject:image forKey:key cost:cost];
        }
    
        if (toDisk) {
            dispatch_async(self.ioQueue, ^{
                NSData *data = imageData;
    
                if (image && (recalculate || !data)) {
    #if TARGET_OS_IPHONE
                    // We need to determine if the image is a PNG or a JPEG
                    // PNGs are easier to detect because they have a unique signature (http://www.w3.org/TR/PNG-Structure.html)
                    // The first eight bytes of a PNG file always contain the following (decimal) values:
                    // 137 80 78 71 13 10 26 10
    
                    // If the imageData is nil (i.e. if trying to save a UIImage directly or the image was transformed on download)
                    // and the image has an alpha channel, we will consider it PNG to avoid losing the transparency
                    int alphaInfo = CGImageGetAlphaInfo(image.CGImage);
                    BOOL hasAlpha = !(alphaInfo == kCGImageAlphaNone ||
                                      alphaInfo == kCGImageAlphaNoneSkipFirst ||
                                      alphaInfo == kCGImageAlphaNoneSkipLast);
                    BOOL imageIsPng = hasAlpha;
    
                    // But if we have an image data, we will look at the preffix
                    if ([imageData length] >= [kPNGSignatureData length]) {
                        imageIsPng = ImageDataHasPNGPreffix(imageData);
                    }
    
                    if (imageIsPng) {
                        data = UIImagePNGRepresentation(image);
                    }
                    else {
                        data = UIImageJPEGRepresentation(image, (CGFloat)1.0);
                    }
    #else
                    data = [NSBitmapImageRep representationOfImageRepsInArray:image.representations usingType: NSJPEGFileType properties:nil];
    #endif
                }
    
                if (data) {
                    if (![_fileManager fileExistsAtPath:_diskCachePath]) {
                        [_fileManager createDirectoryAtPath:_diskCachePath withIntermediateDirectories:YES attributes:nil error:NULL];
                    }
    
                    // get cache Path for image key
                    NSString *cachePathForKey = [self defaultCachePathForKey:key];
                    // transform to NSUrl
                    NSURL *fileURL = [NSURL fileURLWithPath:cachePathForKey];
    
                    [_fileManager createFileAtPath:cachePathForKey contents:data attributes:nil];
    
                    // disable iCloud backup
                    if (self.shouldDisableiCloud) {
                        [fileURL setResourceValue:[NSNumber numberWithBool:YES] forKey:NSURLIsExcludedFromBackupKey error:nil];
                    }
                }
            });
        }
    }
    

    c、下面对上面缓存机制进行分析:

    它会根据jpg和png图片,把不同的图片格式转化为NSData,然后再根据diskCachePath创建一个文件夹,最后把数据保存在沙盒里。

    备注:这个我昨天写的实例不谋而合,虽然没有人家这个容错和各方面考虑的周到,但是思想还是差不多的,明天会看一下,SDWebImage是如何实现gif图片显示的。顺便在自己的组件上实现一下~~

    相关文章

      网友评论

          本文标题:研究一下开源框架SDWebImage

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