Commit 00cc824399ac6138289af1afc5f399f26d755c75

Authored by 王帅
0 parents

no message

CNLiveImageCache.h 0 → 100644
  1 +++ a/CNLiveImageCache.h
  1 +//
  2 +// CNLiveImageCache.h
  3 +// WSWebImageDemo
  4 +//
  5 +// Created by 王帅 on 16/7/19.
  6 +// Copyright © 2016年 王帅. All rights reserved.
  7 +//
  8 +
  9 +#import <Foundation/Foundation.h>
  10 +#import <UIKit/UIKit.h>
  11 +#import "CNLiveWebImageBlock.h"
  12 +
  13 +//typedef void(^CNLiveWebImageQueryCompletedBlock)(UIImage *image, CNLiveImageCacheType type);
  14 +typedef void(^CNLiveCompletedBlock)();
  15 +
  16 +@interface CNLiveImageCache : NSObject
  17 +
  18 ++ (CNLiveImageCache *)sharedImageCache;
  19 +
  20 +- (void)storeImage:(UIImage *)image forKey:(NSString *)key toDisk:(BOOL)toDisk;
  21 +
  22 +- (UIImage *)imageFromMemoryCacheForKey:(NSString *)key;
  23 +
  24 +- (UIImage *)imageFromDiskCacheForKey:(NSString *)key;
  25 +
  26 +- (BOOL)queryDiskCacheForKey:(NSString *)key done:(CNLiveWebImageQueryCompletedBlock)doneBlock;
  27 +
  28 +- (void)removeCacheForKey:(NSString *)key done:(CNLiveCompletedBlock)completed;
  29 +
  30 +- (long long)diskCacheSize;
  31 +
  32 +- (void)clearMemory;
  33 +
  34 +- (void)clearDisk;
  35 +
  36 +@end
CNLiveImageCache.m 0 → 100644
  1 +++ a/CNLiveImageCache.m
  1 +//
  2 +// CNLiveImageCache.m
  3 +// WSWebImageDemo
  4 +//
  5 +// Created by 王帅 on 16/7/19.
  6 +// Copyright © 2016年 王帅. All rights reserved.
  7 +//
  8 +
  9 +#import "CNLiveImageCache.h"
  10 +#import <CommonCrypto/CommonDigest.h>
  11 +#import "UIImage+MultiFormat.h"
  12 +
  13 +FOUNDATION_STATIC_INLINE NSUInteger CNLiveCacheCostForImage(UIImage *image) {
  14 + return image.size.height * image.size.width * image.scale * image.scale;
  15 +}
  16 +
  17 +typedef void(^CNLiveWebImageNoParamsBlock)();
  18 +
  19 +@interface CNLiveImageCache ()
  20 +
  21 +@property (nonatomic, strong) NSCache *memoryCache;
  22 +@property (nonatomic, copy) NSString *diskCachePath;
  23 +@property (nonatomic, strong) dispatch_queue_t ioQueue;
  24 +
  25 +@end
  26 +
  27 +@implementation CNLiveImageCache
  28 +{
  29 + NSFileManager *_fileManager;
  30 +}
  31 +
  32 ++ (CNLiveImageCache *)sharedImageCache
  33 +{
  34 + static dispatch_once_t onceToken;
  35 + static id instance;
  36 + dispatch_once(&onceToken, ^{
  37 + instance = [self new];
  38 + });
  39 + return instance;
  40 +}
  41 +
  42 +- (id)init {
  43 + return [self initWithNamespace:@"default"];
  44 +}
  45 +
  46 +- (id)initWithNamespace:(NSString *)ns {
  47 + NSString *path = [self makeDiskCachePath:ns];
  48 + return [self initWithNamespace:ns diskCacheDirectory:path];
  49 +}
  50 +
  51 +- (NSString *)makeDiskCachePath:(NSString *)fullNamespace {
  52 + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
  53 + return [paths[0] stringByAppendingString:fullNamespace];
  54 +}
  55 +
  56 +- (id)initWithNamespace:(NSString *)ns diskCacheDirectory:(NSString *)directory {
  57 + if (self = [super init]) {
  58 + NSString *fullNameSpace = [@"com.cnlive.CNLiveImageCache." stringByAppendingString:ns];
  59 + _ioQueue = dispatch_queue_create("com.cnlive.CNLiveImageCacheQueue", DISPATCH_QUEUE_SERIAL);
  60 + _memoryCache = [[NSCache alloc] init];
  61 + _memoryCache.name = fullNameSpace;
  62 +
  63 + if (directory != nil) {
  64 + _diskCachePath = [directory stringByAppendingPathComponent:fullNameSpace];
  65 + }
  66 + else {
  67 + _diskCachePath = [[self makeDiskCachePath:ns] stringByAppendingPathComponent:fullNameSpace];
  68 + }
  69 +
  70 + dispatch_sync(_ioQueue, ^{
  71 + _fileManager = [NSFileManager new];
  72 + });
  73 +
  74 + [[NSNotificationCenter defaultCenter] addObserver:self
  75 + selector:@selector(clearMemory)
  76 + name:UIApplicationDidReceiveMemoryWarningNotification
  77 + object:nil];
  78 +
  79 +// [[NSNotificationCenter defaultCenter] addObserver:self
  80 +// selector:@selector(clearDisk)
  81 +// name:UIApplicationWillTerminateNotification
  82 +// object:nil];
  83 + }
  84 + return self;
  85 +}
  86 +
  87 +- (void)dealloc
  88 +{
  89 + [[NSNotificationCenter defaultCenter] removeObserver:self];
  90 +}
  91 +
  92 +- (void)storeImage:(UIImage *)image forKey:(NSString *)key toDisk:(BOOL)toDisk
  93 +{
  94 + if (!image || !key) {
  95 + return;
  96 + }
  97 +
  98 + NSUInteger cost = CNLiveCacheCostForImage(image);
  99 + [_memoryCache setObject:image forKey:key cost:cost];
  100 +
  101 + if (toDisk) {
  102 + dispatch_async(_ioQueue, ^{
  103 + NSData *data = UIImageJPEGRepresentation(image, 1.0);
  104 +
  105 + if (data) {
  106 + if (![_fileManager fileExistsAtPath:_diskCachePath]) {
  107 + [_fileManager createDirectoryAtPath:_diskCachePath withIntermediateDirectories:YES attributes:nil error:NULL];
  108 + }
  109 + NSString *cachePathForKey = [self defaultCachePathForKey:key];
  110 + [_fileManager createFileAtPath:cachePathForKey contents:data attributes:nil];
  111 + }
  112 + });
  113 + }
  114 +}
  115 +
  116 +- (UIImage *)imageFromMemoryCacheForKey:(NSString *)key
  117 +{
  118 + return [self.memoryCache objectForKey:key];
  119 +}
  120 +
  121 +- (UIImage *)imageFromDiskCacheForKey:(NSString *)key
  122 +{
  123 + UIImage *memoryImage = [self imageFromMemoryCacheForKey:key];
  124 + if (memoryImage) {
  125 + return memoryImage;
  126 + }
  127 +
  128 + NSData *diskData = [self getDiskImageDataWithKey:key];
  129 + if (diskData) {
  130 + return [UIImage ws_imageWithData:diskData];
  131 + }
  132 +
  133 + return nil;
  134 +}
  135 +
  136 +- (BOOL)queryDiskCacheForKey:(NSString *)key done:(CNLiveWebImageQueryCompletedBlock)doneBlock
  137 +{
  138 + if (!doneBlock) {
  139 + return NO;
  140 + }
  141 + if (!key) {
  142 + doneBlock(nil, CNLiveImageCacheTypeNone);
  143 + return NO;
  144 + }
  145 +
  146 + UIImage *memoryImage = [self imageFromMemoryCacheForKey:key];
  147 + if (memoryImage) {
  148 + doneBlock(memoryImage, CNLiveImageCacheTypeMemory);
  149 + return YES;
  150 + }
  151 +
  152 + UIImage *diskImage = [self imageFromDiskCacheForKey:key];
  153 + if (diskImage) {
  154 + doneBlock(diskImage, CNLiveImageCacheTypeDisk);
  155 + return YES;
  156 + }
  157 +
  158 + doneBlock(nil, CNLiveImageCacheTypeNone);
  159 + return NO;
  160 +
  161 +}
  162 +
  163 +- (void)removeCacheForKey:(NSString *)key done:(CNLiveCompletedBlock)completed
  164 +{
  165 + if (!key || !completed) {
  166 + return;
  167 + }
  168 +
  169 + if ([self imageFromMemoryCacheForKey:key]) {
  170 + [self.memoryCache removeObjectForKey:key];
  171 + }
  172 +
  173 + if ([self imageFromDiskCacheForKey:key]) {
  174 + NSString *cachePathForKey = [self defaultCachePathForKey:key];
  175 + [_fileManager removeItemAtPath:cachePathForKey error:nil];
  176 + }
  177 +
  178 + completed();
  179 +}
  180 +
  181 +- (long long)diskCacheSize
  182 +{
  183 + if ([_fileManager fileExistsAtPath:self.diskCachePath]) {
  184 + NSArray *subPathArray = [_fileManager subpathsAtPath:self.diskCachePath];
  185 + if (subPathArray && subPathArray.count > 0) {
  186 + long long totalCacheSize = 0;
  187 + for (NSString *subPath in subPathArray) {
  188 + NSString *fullPath = [self.diskCachePath stringByAppendingPathComponent:subPath];
  189 + NSDictionary *cacheSizeDic = [_fileManager attributesOfItemAtPath:fullPath error:nil];
  190 + totalCacheSize += [cacheSizeDic fileSize];
  191 + }
  192 + return totalCacheSize;
  193 + }
  194 + }
  195 + return 0;
  196 +}
  197 +
  198 +- (void)clearMemory
  199 +{
  200 + [self.memoryCache removeAllObjects];
  201 +}
  202 +
  203 +- (void)clearDisk
  204 +{
  205 + [self clearDiskOnCompletion:nil];
  206 +}
  207 +
  208 +- (void)clearDiskOnCompletion:(CNLiveWebImageNoParamsBlock)completion
  209 +{
  210 + dispatch_async(self.ioQueue, ^{
  211 + [_fileManager removeItemAtPath:self.diskCachePath error:nil];
  212 + [_fileManager createDirectoryAtPath:self.diskCachePath withIntermediateDirectories:YES attributes:nil error:NULL];
  213 +
  214 + if (completion) {
  215 + dispatch_async(dispatch_get_main_queue(), ^{
  216 + completion();
  217 + });
  218 + }
  219 + });
  220 +}
  221 +
  222 +#pragma mark <PrivateMethod>
  223 +- (NSData *)getDiskImageDataWithKey:(NSString *)key
  224 +{
  225 + NSString *filePath = [self defaultCachePathForKey:key];
  226 + NSData *imageData = [NSData dataWithContentsOfFile:filePath];
  227 + return imageData;
  228 +}
  229 +
  230 +- (NSString *)defaultCachePathForKey:(NSString *)key
  231 +{
  232 + return [self cachePathForKey:key inPath:self.diskCachePath];
  233 +}
  234 +
  235 +- (NSString *)cachePathForKey:(NSString *)key inPath:(NSString *)path
  236 +{
  237 + NSString *fileName = [self cachedFileNameForKey:key];
  238 + return [path stringByAppendingPathComponent:fileName];
  239 +}
  240 +
  241 +- (NSString *)cachedFileNameForKey:(NSString *)key {
  242 + const char *str = [key UTF8String];
  243 + if (str == NULL) {
  244 + str = "";
  245 + }
  246 + unsigned char r[CC_MD5_DIGEST_LENGTH];
  247 + CC_MD5(str, (CC_LONG)strlen(str), r);
  248 + NSString *filename = [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
  249 + r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7], r[8], r[9], r[10], r[11], r[12], r[13], r[14], r[15]];
  250 +
  251 + return filename;
  252 +}
  253 +
  254 +@end
CNLiveWebImageBlock.h 0 → 100644
  1 +++ a/CNLiveWebImageBlock.h
  1 +//
  2 +// CNLiveWebImageBlock.h
  3 +// WSWebImageDemo
  4 +//
  5 +// Created by 王帅 on 16/7/27.
  6 +// Copyright © 2016年 王帅. All rights reserved.
  7 +//
  8 +
  9 +#ifndef CNLiveWebImageBlock_h
  10 +#define CNLiveWebImageBlock_h
  11 +
  12 +typedef NS_ENUM(NSUInteger, CNLiveImageCacheType) {
  13 + CNLiveImageCacheTypeNone,
  14 + CNLiveImageCacheTypeMemory,
  15 + CNLiveImageCacheTypeDisk
  16 +};
  17 +
  18 +typedef void(^CNLiveDownloadProgressBlock)(NSInteger receivedSize, NSInteger expectedSize);
  19 +typedef void(^CNLiveDownloadCompletedBlock)(UIImage *image, NSData *data, NSError *error, BOOL finished);
  20 +
  21 +typedef void(^CNLiveWebImageQueryCompletedBlock)(UIImage *image, CNLiveImageCacheType type);
  22 +typedef void(^CNLiveCompletedBlock)();
  23 +typedef void(^CNLiveWebImageNoParamsBlock)();
  24 +
  25 +#endif /* CNLiveWebImageBlock_h */
CNLiveWebImageDownload.h 0 → 100644
  1 +++ a/CNLiveWebImageDownload.h
  1 +//
  2 +// CNLiveWebImageDownload.h
  3 +// WSWebImageDemo
  4 +//
  5 +// Created by 王帅 on 16/7/14.
  6 +// Copyright © 2016年 王帅. All rights reserved.
  7 +//
  8 +
  9 +#import <Foundation/Foundation.h>
  10 +#import <UIKit/UIKit.h>
  11 +#import "CNLiveWebImageOperation.h"
  12 +#import "CNLiveWebImageBlock.h"
  13 +
  14 +typedef NS_OPTIONS(NSUInteger, CNLiveWebImageDownloadOptions) {
  15 + CNLiveWebImageDownloadProgressiveDownload = 1 << 0,
  16 + CNLiveWebImageDownloadContinueInBackground = 1 << 1
  17 +};
  18 +
  19 +@interface CNLiveWebImageDownload : NSObject
  20 +
  21 ++ (CNLiveWebImageDownload *)sharedDownload;
  22 +
  23 +- (id <CNLiveWebImageOperation>)downloadWebImageWithURL:(NSURL *)url options:(CNLiveWebImageDownloadOptions)options progress:(CNLiveDownloadProgressBlock)progress completed:(CNLiveDownloadCompletedBlock)completed;
  24 +
  25 +@end
CNLiveWebImageDownload.m 0 → 100644
  1 +++ a/CNLiveWebImageDownload.m
  1 +//
  2 +// CNLiveWebImageDownload.m
  3 +// WSWebImageDemo
  4 +//
  5 +// Created by 王帅 on 16/7/14.
  6 +// Copyright © 2016年 王帅. All rights reserved.
  7 +//
  8 +
  9 +#import "CNLiveWebImageDownload.h"
  10 +#import "CNLiveWebImageDownloadOperation.h"
  11 +
  12 +@interface CNLiveWebImageDownload ()
  13 +
  14 +@property (nonatomic, strong) NSOperationQueue *downloadQueue;
  15 +
  16 +@end
  17 +
  18 +@implementation CNLiveWebImageDownload
  19 +
  20 ++ (CNLiveWebImageDownload *)sharedDownload
  21 +{
  22 + static dispatch_once_t once;
  23 + static id instance;
  24 + dispatch_once(&once, ^{
  25 + instance = [self new];
  26 + });
  27 + return instance;
  28 +}
  29 +
  30 +- (instancetype)init
  31 +{
  32 + if ((self = [super init])) {
  33 + _downloadQueue = [NSOperationQueue new];
  34 + _downloadQueue.maxConcurrentOperationCount = 6;
  35 + }
  36 + return self;
  37 +}
  38 +
  39 +- (void)dealloc
  40 +{
  41 + [self.downloadQueue cancelAllOperations];
  42 +}
  43 +
  44 +- (id<CNLiveWebImageOperation>)downloadWebImageWithURL:(NSURL *)url options:(CNLiveWebImageDownloadOptions)options progress:(CNLiveDownloadProgressBlock)progress completed:(CNLiveDownloadCompletedBlock)completed
  45 +{
  46 + CNLiveWebImageDownloadOperation *operation;
  47 + operation = [[CNLiveWebImageDownloadOperation alloc] initWithURL:url
  48 + options:options
  49 + progress:progress
  50 + completed:completed];
  51 + [self.downloadQueue addOperation:operation];
  52 + return (id <CNLiveWebImageOperation>)operation;
  53 +}
  54 +@end
CNLiveWebImageDownloadOperation.h 0 → 100644
  1 +++ a/CNLiveWebImageDownloadOperation.h
  1 +//
  2 +// CNLiveWebImageDownloadOperation.h
  3 +// WSWebImageDemo
  4 +//
  5 +// Created by 王帅 on 16/7/25.
  6 +// Copyright © 2016年 王帅. All rights reserved.
  7 +//
  8 +
  9 +#import <Foundation/Foundation.h>
  10 +#import "CNLiveWebImageDownload.h"
  11 +#import "CNLiveWebImageBlock.h"
  12 +
  13 +@interface CNLiveWebImageDownloadOperation : NSOperation
  14 +
  15 +- (id)initWithURL:(NSURL *)url options:(CNLiveWebImageDownloadOptions)options progress:(CNLiveDownloadProgressBlock)progress completed:(CNLiveDownloadCompletedBlock)completed;
  16 +
  17 +@end
CNLiveWebImageDownloadOperation.m 0 → 100644
  1 +++ a/CNLiveWebImageDownloadOperation.m
  1 +//
  2 +// CNLiveWebImageDownloadOperation.m
  3 +// WSWebImageDemo
  4 +//
  5 +// Created by 王帅 on 16/7/25.
  6 +// Copyright © 2016年 王帅. All rights reserved.
  7 +//
  8 +
  9 +#import "CNLiveWebImageDownloadOperation.h"
  10 +#import "CNLiveWebImageOperation.h"
  11 +#import <ImageIO/ImageIO.h>
  12 +#import "UIImage+MultiFormat.h"
  13 +
  14 +#define CNLiveWebImageBackgroundSessionIdentifier @"CNLiveWebImageBackgroundSessionIdentifier"
  15 +
  16 +@interface CNLiveWebImageDownloadOperation ()<CNLiveWebImageOperation, NSURLSessionDataDelegate, NSURLSessionTaskDelegate, NSURLSessionDelegate>
  17 +
  18 +@property (nonatomic, copy) CNLiveDownloadProgressBlock progressBlock;
  19 +@property (nonatomic, copy) CNLiveDownloadCompletedBlock completedBlock;
  20 +@property (nonatomic, assign) CNLiveWebImageDownloadOptions options;
  21 +@property (nonatomic, strong) NSURL *url;
  22 +
  23 +@property (nonatomic, strong) NSURLSessionConfiguration *config;
  24 +@property (nonatomic, strong) NSURLSession *session;
  25 +@property (nonatomic, strong) NSURLSessionDataTask *dataTask;
  26 +@property (nonatomic, assign) NSInteger expectedSize;
  27 +@property (nonatomic, strong) NSMutableData *imageData;
  28 +@property (nonatomic, strong) NSURLResponse *response;
  29 +
  30 +@end
  31 +
  32 +@implementation CNLiveWebImageDownloadOperation
  33 +
  34 +- (id)initWithURL:(NSURL *)url options:(CNLiveWebImageDownloadOptions)options progress:(CNLiveDownloadProgressBlock)progress completed:(CNLiveDownloadCompletedBlock)completed
  35 +{
  36 + if ((self = [super init])) {
  37 + _url = url;
  38 + _progressBlock = progress;
  39 + _completedBlock = completed;
  40 + _options = options;
  41 + }
  42 + return self;
  43 +}
  44 +
  45 +- (void)start
  46 +{
  47 + @synchronized (self) {
  48 + if (self.isCancelled) {
  49 + return;
  50 + }
  51 + }
  52 + self.dataTask = [self.session dataTaskWithURL:self.url];
  53 + [self.dataTask resume];
  54 + [self.session finishTasksAndInvalidate];
  55 +}
  56 +
  57 +- (NSURLSessionConfiguration *)config
  58 +{
  59 + if (!_config) {
  60 + if (self.options & CNLiveWebImageDownloadContinueInBackground) {
  61 + _config = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:CNLiveWebImageBackgroundSessionIdentifier];
  62 + }
  63 + else {
  64 + _config = [NSURLSessionConfiguration ephemeralSessionConfiguration];
  65 + }
  66 + }
  67 + return _config;
  68 +}
  69 +
  70 +- (NSURLSession *)session
  71 +{
  72 + if (!_session) {
  73 + _session = [NSURLSession sessionWithConfiguration:self.config delegate:self delegateQueue:[NSOperationQueue mainQueue]];
  74 + }
  75 + return _session;
  76 +}
  77 +
  78 +#pragma mark <NSURLSessionDataDelegate>
  79 +- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
  80 +{
  81 + if (![response respondsToSelector:@selector(statusCode)] || ([((NSHTTPURLResponse *)response) statusCode] < 400 && [((NSHTTPURLResponse *)response) statusCode] != 304)) {
  82 + NSInteger expected = response.expectedContentLength > 0 ? (NSInteger)response.expectedContentLength : 0;
  83 + self.expectedSize = expected;
  84 + if (self.progressBlock) {
  85 + self.progressBlock(0, expected);
  86 + }
  87 +
  88 + self.imageData = [[NSMutableData alloc] initWithCapacity:expected];
  89 + self.response = response;
  90 + completionHandler(NSURLSessionResponseAllow);
  91 + }
  92 + else {
  93 +
  94 + [self.dataTask cancel];
  95 +
  96 + dispatch_async(dispatch_get_main_queue(), ^{
  97 + if (self.completedBlock) {
  98 + self.completedBlock(nil, nil, [NSError errorWithDomain:NSURLErrorDomain code:[((NSHTTPURLResponse *)response) statusCode] userInfo:nil], YES);
  99 + }
  100 + });
  101 + }
  102 +}
  103 +
  104 +- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
  105 +{
  106 + [self.imageData appendData:data];
  107 + if (self.options & CNLiveWebImageDownloadProgressiveDownload && self.completedBlock) {
  108 + const NSInteger totalSize = self.imageData.length;
  109 + CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)self.imageData, NULL);
  110 + if (totalSize < self.expectedSize) {
  111 + CGImageRef partialImageRef = CGImageSourceCreateImageAtIndex(imageSource, 0, NULL);
  112 + if (partialImageRef) {
  113 + UIImage *image = [UIImage imageWithCGImage:partialImageRef];
  114 + CGImageRelease(partialImageRef);
  115 + dispatch_async(dispatch_get_main_queue(), ^{
  116 + if (self.completedBlock) {
  117 + self.completedBlock(image, self.imageData, nil, NO);
  118 + }
  119 + });
  120 + }
  121 + }
  122 +
  123 + CFRelease(imageSource);
  124 + }
  125 +
  126 + dispatch_async(dispatch_get_main_queue(), ^{
  127 + if (self.progressBlock) {
  128 + self.progressBlock(self.imageData.length, self.expectedSize);
  129 + }
  130 + });
  131 +}
  132 +
  133 +- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
  134 +{
  135 + if (error) {
  136 + dispatch_async(dispatch_get_main_queue(), ^{
  137 + if (self.completedBlock) {
  138 + self.completedBlock(nil, nil, error, NO);
  139 + }
  140 + });
  141 + }
  142 + else {
  143 + dispatch_async(dispatch_get_main_queue(), ^{
  144 + if (self.completedBlock) {
  145 + self.completedBlock([UIImage ws_imageWithData:self.imageData], self.imageData, nil, YES);
  146 + }
  147 + });
  148 + }
  149 +}
  150 +
  151 +- (void)cancel
  152 +{
  153 + if (self.session) {
  154 + [self.session invalidateAndCancel];
  155 + }
  156 + self.completedBlock = nil;
  157 + self.progressBlock = nil;
  158 + self.session = nil;
  159 + self.imageData = nil;
  160 +}
  161 +
  162 +
  163 +
  164 +
  165 +
  166 +
  167 +
  168 +
  169 +
  170 +
  171 +
  172 +
  173 +
  174 +
  175 +@end
CNLiveWebImageManager.h 0 → 100644
  1 +++ a/CNLiveWebImageManager.h
  1 +//
  2 +// CNLiveWebImageManager.h
  3 +// WSWebImageDemo
  4 +//
  5 +// Created by 王帅 on 16/7/27.
  6 +// Copyright © 2016年 王帅. All rights reserved.
  7 +//
  8 +
  9 +#import <Foundation/Foundation.h>
  10 +#import <UIKit/UIKit.h>
  11 +#import "CNLiveWebImageBlock.h"
  12 +#import "CNLiveWebImageOperation.h"
  13 +
  14 +typedef NS_OPTIONS(NSUInteger, CNLiveWebImageOptions) {
  15 + CNLiveWebImageRetryFailed = 1 << 0,
  16 + CNLiveWebImageCacheMemoryOnly = 1 << 1,
  17 + CNLiveWebImageProgressiveDownload = 1 << 2,
  18 + CNLiveWebImageContinueInBackground = 1 << 3
  19 +};
  20 +
  21 +@interface CNLiveWebImageManager : NSObject
  22 +
  23 ++ (nonnull id)sharedManager;
  24 +
  25 +- (nonnull id <CNLiveWebImageOperation>)downloadWebImageWithURL:(nonnull NSURL *)url options:(CNLiveWebImageOptions)options progress:(nonnull CNLiveDownloadProgressBlock)progress completed:(nonnull CNLiveDownloadCompletedBlock)completed;
  26 +
  27 +- (void)storeImage:(nonnull UIImage *)image imageUrl:(nonnull NSURL *)url toDisk:(BOOL)toDisk;
  28 +
  29 +- (nullable UIImage *)imageFromMemoryCacheWithImageUrl:(nonnull NSURL *)url;
  30 +
  31 +- (nullable UIImage *)imageFromDiskCacheWithImageUrl:(nonnull NSURL *)url;
  32 +
  33 +- (BOOL)queryDiskCacheWithImageUrl:(nonnull NSURL *)url done:(nonnull CNLiveWebImageQueryCompletedBlock)doneBlock;
  34 +
  35 +- (void)removeCacheWithUrl:(nonnull NSURL *)url done:(nonnull CNLiveCompletedBlock)completed;
  36 +
  37 +- (long long)diskCacheSize;
  38 +
  39 +- (void)clearMemory;
  40 +
  41 +- (void)clearDisk;
  42 +
  43 +@end
CNLiveWebImageManager.m 0 → 100644
  1 +++ a/CNLiveWebImageManager.m
  1 +//
  2 +// CNLiveWebImageManager.m
  3 +// WSWebImageDemo
  4 +//
  5 +// Created by 王帅 on 16/7/27.
  6 +// Copyright © 2016年 王帅. All rights reserved.
  7 +//
  8 +
  9 +#import "CNLiveWebImageManager.h"
  10 +#import "CNLiveWebImageDownload.h"
  11 +#import "CNLiveImageCache.h"
  12 +
  13 +@interface CNLiveWebImageManager ()
  14 +
  15 +@property (nonatomic, strong) CNLiveImageCache *imageCache;
  16 +@property (nonatomic, strong) NSMutableSet *failedURLs;
  17 +
  18 +@end
  19 +
  20 +@implementation CNLiveWebImageManager
  21 +
  22 ++ (id)sharedManager
  23 +{
  24 + static id manager;
  25 + static dispatch_once_t once;
  26 + dispatch_once(&once, ^{
  27 + manager = [self new];
  28 + });
  29 + return manager;
  30 +}
  31 +
  32 +- (instancetype)init
  33 +{
  34 + if ((self = [super init])) {
  35 + _imageCache = [CNLiveImageCache sharedImageCache];
  36 + _failedURLs = [NSMutableSet new];
  37 + }
  38 + return self;
  39 +}
  40 +
  41 +- (id<CNLiveWebImageOperation>)downloadWebImageWithURL:(NSURL *)url options:(CNLiveWebImageOptions)options progress:(CNLiveDownloadProgressBlock)progress completed:(CNLiveDownloadCompletedBlock)completed
  42 +{
  43 + if ([url isKindOfClass:NSString.class]) {
  44 + url = [NSURL URLWithString:(NSString *)url];
  45 + }
  46 + if (![url isKindOfClass:NSURL.class]) {
  47 + url = nil;
  48 + }
  49 +
  50 + BOOL isFailedUrl = NO;
  51 + @synchronized (self.failedURLs) {
  52 + isFailedUrl = [self.failedURLs containsObject:url];
  53 + }
  54 + if (!url || (!(options & CNLiveWebImageRetryFailed) && isFailedUrl)) {
  55 + NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorFileDoesNotExist userInfo:nil];
  56 + completed(nil, nil, error, YES);
  57 + }
  58 +
  59 + BOOL hasCacheImage = [self.imageCache queryDiskCacheForKey:url.absoluteString done:^(UIImage *image, CNLiveImageCacheType type) {
  60 + if (image) {
  61 + completed(image,UIImageJPEGRepresentation(image, 1.0), nil, YES);
  62 + }
  63 + }];;
  64 +
  65 + if (hasCacheImage) {
  66 + return nil;
  67 + }
  68 +
  69 +
  70 + CNLiveWebImageDownloadOptions downloadOptions = 0;
  71 + if (options & CNLiveWebImageProgressiveDownload) downloadOptions |= CNLiveWebImageDownloadProgressiveDownload;
  72 + if (options & CNLiveWebImageContinueInBackground) downloadOptions |= CNLiveWebImageDownloadContinueInBackground;
  73 + id <CNLiveWebImageOperation> operation = [[CNLiveWebImageDownload sharedDownload] downloadWebImageWithURL:url options:downloadOptions progress:progress completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) {
  74 + if (error) {
  75 + BOOL shouldBeFailedURLAlliOSVersion = (error.code != NSURLErrorNotConnectedToInternet && error.code != NSURLErrorCancelled && error.code != NSURLErrorTimedOut);
  76 + BOOL shouldBeFailedURLiOS7 = (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_6_1 && error.code != NSURLErrorInternationalRoamingOff && error.code != NSURLErrorCallIsActive && error.code != NSURLErrorDataNotAllowed);
  77 + if (shouldBeFailedURLAlliOSVersion || shouldBeFailedURLiOS7) {
  78 + @synchronized (self.failedURLs) {
  79 + [self.failedURLs addObject:url];
  80 + }
  81 + }
  82 + }
  83 + else {
  84 + if ((options & CNLiveWebImageRetryFailed)) {
  85 + @synchronized (self.failedURLs) {
  86 + [self.failedURLs removeObject:url];
  87 + }
  88 + }
  89 +
  90 + BOOL cacheOnDisk = !(options & CNLiveWebImageCacheMemoryOnly);
  91 + if (image && finished) {
  92 + if (cacheOnDisk) {
  93 + [self.imageCache storeImage:image forKey:[url absoluteString] toDisk:YES];
  94 + }
  95 + else {
  96 + [self.imageCache storeImage:image forKey:[url absoluteString] toDisk:NO];
  97 + }
  98 + }
  99 +
  100 + completed(image, data, error, finished);
  101 + }
  102 +
  103 + }];
  104 + return operation;
  105 +}
  106 +
  107 +- (void)storeImage:(UIImage *)image imageUrl:(NSURL *)url toDisk:(BOOL)toDisk
  108 +{
  109 + [self.imageCache storeImage:image forKey:url.absoluteString toDisk:toDisk];
  110 +}
  111 +
  112 +- (UIImage *)imageFromMemoryCacheWithImageUrl:(NSURL *)url
  113 +{
  114 + return [self.imageCache imageFromMemoryCacheForKey:url.absoluteString];
  115 +}
  116 +
  117 +- (UIImage *)imageFromDiskCacheWithImageUrl:(NSURL *)url
  118 +{
  119 + return [self.imageCache imageFromDiskCacheForKey:url.absoluteString];
  120 +}
  121 +
  122 +- (BOOL)queryDiskCacheWithImageUrl:(NSURL *)url done:(CNLiveWebImageQueryCompletedBlock)doneBlock
  123 +{
  124 + return [self.imageCache queryDiskCacheForKey:url.absoluteString done:doneBlock];
  125 +}
  126 +
  127 +- (void)removeCacheWithUrl:(NSURL *)url done:(CNLiveCompletedBlock)completed
  128 +{
  129 + [self.imageCache removeCacheForKey:url.absoluteString done:completed];
  130 +}
  131 +
  132 +- (long long)diskCacheSize
  133 +{
  134 + return [self.imageCache diskCacheSize];
  135 +}
  136 +
  137 +- (void)clearMemory
  138 +{
  139 + [self.imageCache clearMemory];
  140 +}
  141 +
  142 +- (void)clearDisk
  143 +{
  144 + [self.imageCache clearDisk];
  145 +}
  146 +
  147 +@end
CNLiveWebImageOperation.h 0 → 100644
  1 +++ a/CNLiveWebImageOperation.h
  1 +//
  2 +// CNLiveWebImageOperation.h
  3 +// WSWebImageDemo
  4 +//
  5 +// Created by 王帅 on 16/7/19.
  6 +// Copyright © 2016年 王帅. All rights reserved.
  7 +//
  8 +
  9 +#import <Foundation/Foundation.h>
  10 +
  11 +@protocol CNLiveWebImageOperation <NSObject>
  12 +
  13 +- (void)cancel;
  14 +
  15 +@end
NSData+ImageContentType.h 0 → 100644
  1 +++ a/NSData+ImageContentType.h
  1 +//
  2 +// NSData+ImageContentType.h
  3 +// WSWebImageDemo
  4 +//
  5 +// Created by 王帅 on 16/7/21.
  6 +// Copyright © 2016年 王帅. All rights reserved.
  7 +//
  8 +
  9 +#import <Foundation/Foundation.h>
  10 +
  11 +@interface NSData (ImageContentType)
  12 +
  13 ++ (NSString *)ws_imageContentTypeWithData:(NSData *)data;
  14 +
  15 +@end
NSData+ImageContentType.m 0 → 100644
  1 +++ a/NSData+ImageContentType.m
  1 +//
  2 +// NSData+ImageContentType.m
  3 +// WSWebImageDemo
  4 +//
  5 +// Created by 王帅 on 16/7/21.
  6 +// Copyright © 2016年 王帅. All rights reserved.
  7 +//
  8 +
  9 +#import "NSData+ImageContentType.h"
  10 +
  11 +@implementation NSData (ImageContentType)
  12 +
  13 ++ (NSString *)ws_imageContentTypeWithData:(NSData *)data
  14 +{
  15 + uint8_t c;
  16 + [data getBytes:&c length:1];
  17 + switch (c) {
  18 + case 0xFF:
  19 + return @"image/jpeg";
  20 + case 0x89:
  21 + return @"image/png";
  22 + case 0x47:
  23 + return @"image/gif";
  24 + case 0x49:
  25 + case 0x4D:
  26 + return @"image/tiff";
  27 + case 0x52:
  28 +
  29 + if ([data length] < 12) {
  30 + return nil;
  31 + }
  32 +
  33 + NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(0, 12)] encoding:NSASCIIStringEncoding];
  34 + if ([testString hasPrefix:@"RIFF"] && [testString hasSuffix:@"WEBP"]) {
  35 + return @"image/webp";
  36 + }
  37 +
  38 + return nil;
  39 + }
  40 + return nil;
  41 +}
  42 +
  43 +@end
UIImage+MultiFormat.h 0 → 100644
  1 +++ a/UIImage+MultiFormat.h
  1 +//
  2 +// UIImage+MultiFormat.h
  3 +// WSWebImageDemo
  4 +//
  5 +// Created by 王帅 on 16/7/21.
  6 +// Copyright © 2016年 王帅. All rights reserved.
  7 +//
  8 +
  9 +#import <UIKit/UIKit.h>
  10 +
  11 +@interface UIImage (MultiFormat)
  12 +
  13 ++ (UIImage *)ws_imageWithData:(NSData *)data;
  14 +
  15 +@end
UIImage+MultiFormat.m 0 → 100644
  1 +++ a/UIImage+MultiFormat.m
  1 +//
  2 +// UIImage+MultiFormat.m
  3 +// WSWebImageDemo
  4 +//
  5 +// Created by 王帅 on 16/7/21.
  6 +// Copyright © 2016年 王帅. All rights reserved.
  7 +//
  8 +
  9 +#import "UIImage+MultiFormat.h"
  10 +#import "NSData+ImageContentType.h"
  11 +
  12 +@implementation UIImage (MultiFormat)
  13 +
  14 ++ (UIImage *)ws_imageWithData:(NSData *)data
  15 +{
  16 + if (!data) {
  17 + return nil;
  18 + }
  19 + UIImage *image;
  20 + NSString *imageContentType = [NSData ws_imageContentTypeWithData:data];
  21 +
  22 + if ([imageContentType isEqualToString:@"image/gif"]) {
  23 + //TODO 处理GIF图片
  24 + }
  25 + else if ([imageContentType isEqualToString:@"image/webp"]) {
  26 + //TODO 处理WEBP图片
  27 + }
  28 + else {
  29 + image = [[UIImage alloc] initWithData:data];
  30 + }
  31 + return image;
  32 +}
  33 +
  34 +@end
UIImageView+WebCache.h 0 → 100644
  1 +++ a/UIImageView+WebCache.h
  1 +//
  2 +// UIImageView+WebCache.h
  3 +// WSWebImageDemo
  4 +//
  5 +// Created by 王帅 on 16/7/26.
  6 +// Copyright © 2016年 王帅. All rights reserved.
  7 +//
  8 +
  9 +#import <UIKit/UIKit.h>
  10 +#import "CNLiveWebImageManager.h"
  11 +
  12 +@interface UIImageView (WebCache)
  13 +
  14 +- (void)ws_setImageWithUrl:(NSURL *)url;
  15 +
  16 +- (void)ws_setImageWithUrl:(NSURL *)url placeholderImage:(UIImage *)placeholder;
  17 +
  18 +@end
UIImageView+WebCache.m 0 → 100644
  1 +++ a/UIImageView+WebCache.m
  1 +//
  2 +// UIImageView+WebCache.m
  3 +// WSWebImageDemo
  4 +//
  5 +// Created by 王帅 on 16/7/26.
  6 +// Copyright © 2016年 王帅. All rights reserved.
  7 +//
  8 +
  9 +#import "UIImageView+WebCache.h"
  10 +#import "CNLiveWebImageBlock.h"
  11 +
  12 +@implementation UIImageView (WebCache)
  13 +
  14 +- (void)ws_setImageWithUrl:(NSURL *)url
  15 +{
  16 + [self ws_setImageWithUrl:url placeholderImage:nil options:0 progress:nil completed:nil];
  17 +}
  18 +
  19 +- (void)ws_setImageWithUrl:(NSURL *)url placeholderImage:(UIImage *)placeholder
  20 +{
  21 + [self ws_setImageWithUrl:url placeholderImage:placeholder options:0 progress:nil completed:nil];
  22 +}
  23 +
  24 +- (void)ws_setImageWithUrl:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(CNLiveWebImageOptions)options progress:(CNLiveDownloadProgressBlock)progress completed:(CNLiveDownloadCompletedBlock)completed
  25 +{
  26 + if (placeholder) {
  27 + self.image = placeholder;
  28 + }
  29 +
  30 + if (url) {
  31 + __weak __typeof(self) weakSelf = self;
  32 + [[CNLiveWebImageManager sharedManager] downloadWebImageWithURL:url
  33 + options:options
  34 + progress:progress
  35 + completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) {
  36 + if (image && !error && finished) {
  37 + weakSelf.image = image;
  38 + }
  39 + }];
  40 + }
  41 + else {
  42 + dispatch_async(dispatch_get_main_queue(), ^{
  43 + NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Trying to load a nil url"}];
  44 + if (completed) {
  45 + completed(nil, nil, error, NO);
  46 + }
  47 + });
  48 + }
  49 +
  50 +}
  51 +
  52 +@end