reformat code (appcode)
This commit is contained in:
parent
c00c2e0ed4
commit
6dc02bd8f7
|
@ -13,53 +13,42 @@ static char operationKey;
|
||||||
|
|
||||||
@implementation MKAnnotationView (WebCache)
|
@implementation MKAnnotationView (WebCache)
|
||||||
|
|
||||||
- (void)setImageWithURL:(NSURL *)url
|
- (void)setImageWithURL:(NSURL *)url {
|
||||||
{
|
|
||||||
[self setImageWithURL:url placeholderImage:nil options:0 completed:nil];
|
[self setImageWithURL:url placeholderImage:nil options:0 completed:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder
|
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder {
|
||||||
{
|
|
||||||
[self setImageWithURL:url placeholderImage:placeholder options:0 completed:nil];
|
[self setImageWithURL:url placeholderImage:placeholder options:0 completed:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options
|
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options {
|
||||||
{
|
|
||||||
[self setImageWithURL:url placeholderImage:placeholder options:options completed:nil];
|
[self setImageWithURL:url placeholderImage:placeholder options:options completed:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setImageWithURL:(NSURL *)url completed:(SDWebImageCompletedBlock)completedBlock
|
- (void)setImageWithURL:(NSURL *)url completed:(SDWebImageCompletedBlock)completedBlock {
|
||||||
{
|
|
||||||
[self setImageWithURL:url placeholderImage:nil options:0 completed:completedBlock];
|
[self setImageWithURL:url placeholderImage:nil options:0 completed:completedBlock];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder completed:(SDWebImageCompletedBlock)completedBlock
|
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder completed:(SDWebImageCompletedBlock)completedBlock {
|
||||||
{
|
|
||||||
[self setImageWithURL:url placeholderImage:placeholder options:0 completed:completedBlock];
|
[self setImageWithURL:url placeholderImage:placeholder options:0 completed:completedBlock];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options completed:(SDWebImageCompletedBlock)completedBlock
|
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options completed:(SDWebImageCompletedBlock)completedBlock {
|
||||||
{
|
|
||||||
[self cancelCurrentImageLoad];
|
[self cancelCurrentImageLoad];
|
||||||
|
|
||||||
self.image = placeholder;
|
self.image = placeholder;
|
||||||
|
|
||||||
if (url)
|
if (url) {
|
||||||
{
|
|
||||||
__weak MKAnnotationView *wself = self;
|
__weak MKAnnotationView *wself = self;
|
||||||
id<SDWebImageOperation> operation = [SDWebImageManager.sharedManager downloadWithURL:url options:options progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished)
|
id <SDWebImageOperation> operation = [SDWebImageManager.sharedManager downloadWithURL:url options:options progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished) {
|
||||||
{
|
|
||||||
if (!wself) return;
|
if (!wself) return;
|
||||||
dispatch_main_sync_safe(^
|
dispatch_main_sync_safe(^{
|
||||||
{
|
|
||||||
__strong MKAnnotationView *sself = wself;
|
__strong MKAnnotationView *sself = wself;
|
||||||
if (!sself) return;
|
if (!sself) return;
|
||||||
if (image)
|
if (image) {
|
||||||
{
|
|
||||||
sself.image = image;
|
sself.image = image;
|
||||||
}
|
}
|
||||||
if (completedBlock && finished)
|
if (completedBlock && finished) {
|
||||||
{
|
|
||||||
completedBlock(image, error, cacheType);
|
completedBlock(image, error, cacheType);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -68,12 +57,10 @@ static char operationKey;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)cancelCurrentImageLoad
|
- (void)cancelCurrentImageLoad {
|
||||||
{
|
|
||||||
// Cancel in progress downloader from queue
|
// Cancel in progress downloader from queue
|
||||||
id<SDWebImageOperation> operation = objc_getAssociatedObject(self, &operationKey);
|
id <SDWebImageOperation> operation = objc_getAssociatedObject(self, &operationKey);
|
||||||
if (operation)
|
if (operation) {
|
||||||
{
|
|
||||||
[operation cancel];
|
[operation cancel];
|
||||||
objc_setAssociatedObject(self, &operationKey, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
objc_setAssociatedObject(self, &operationKey, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,20 +9,19 @@
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
#import "SDWebImageCompat.h"
|
#import "SDWebImageCompat.h"
|
||||||
|
|
||||||
enum SDImageCacheType
|
enum SDImageCacheType {
|
||||||
{
|
|
||||||
/**
|
/**
|
||||||
* The image wasn't available the SDWebImage caches, but was downloaded from the web.
|
* The image wasn't available the SDWebImage caches, but was downloaded from the web.
|
||||||
*/
|
*/
|
||||||
SDImageCacheTypeNone = 0,
|
SDImageCacheTypeNone = 0,
|
||||||
/**
|
/**
|
||||||
* The image was obtained from the disk cache.
|
* The image was obtained from the disk cache.
|
||||||
*/
|
*/
|
||||||
SDImageCacheTypeDisk,
|
SDImageCacheTypeDisk,
|
||||||
/**
|
/**
|
||||||
* The image was obtained from the memory cache.
|
* The image was obtained from the memory cache.
|
||||||
*/
|
*/
|
||||||
SDImageCacheTypeMemory
|
SDImageCacheTypeMemory
|
||||||
};
|
};
|
||||||
typedef enum SDImageCacheType SDImageCacheType;
|
typedef enum SDImageCacheType SDImageCacheType;
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,6 @@
|
||||||
#import "SDWebImageDecoder.h"
|
#import "SDWebImageDecoder.h"
|
||||||
#import "UIImage+MultiFormat.h"
|
#import "UIImage+MultiFormat.h"
|
||||||
#import <CommonCrypto/CommonDigest.h>
|
#import <CommonCrypto/CommonDigest.h>
|
||||||
#import <mach/mach.h>
|
|
||||||
#import <mach/mach_host.h>
|
|
||||||
|
|
||||||
static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week
|
static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week
|
||||||
// PNG signature bytes and data (below)
|
// PNG signature bytes and data (below)
|
||||||
|
@ -19,13 +17,11 @@ static unsigned char kPNGSignatureBytes[8] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A
|
||||||
static NSData *kPNGSignatureData = nil;
|
static NSData *kPNGSignatureData = nil;
|
||||||
|
|
||||||
BOOL ImageDataHasPNGPreffix(NSData *data);
|
BOOL ImageDataHasPNGPreffix(NSData *data);
|
||||||
BOOL ImageDataHasPNGPreffix(NSData *data)
|
|
||||||
{
|
BOOL ImageDataHasPNGPreffix(NSData *data) {
|
||||||
NSUInteger pngSignatureLength = [kPNGSignatureData length];
|
NSUInteger pngSignatureLength = [kPNGSignatureData length];
|
||||||
if ([data length] >= pngSignatureLength)
|
if ([data length] >= pngSignatureLength) {
|
||||||
{
|
if ([[data subdataWithRange:NSMakeRange(0, pngSignatureLength)] isEqualToData:kPNGSignatureData]) {
|
||||||
if ([[data subdataWithRange:NSMakeRange(0, pngSignatureLength)] isEqualToData:kPNGSignatureData])
|
|
||||||
{
|
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,32 +39,26 @@ BOOL ImageDataHasPNGPreffix(NSData *data)
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
@implementation SDImageCache
|
@implementation SDImageCache {
|
||||||
{
|
|
||||||
NSFileManager *_fileManager;
|
NSFileManager *_fileManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (SDImageCache *)sharedImageCache
|
+ (SDImageCache *)sharedImageCache {
|
||||||
{
|
|
||||||
static dispatch_once_t once;
|
static dispatch_once_t once;
|
||||||
static id instance;
|
static id instance;
|
||||||
dispatch_once(&once, ^
|
dispatch_once(&once, ^{
|
||||||
{
|
|
||||||
instance = self.new;
|
instance = self.new;
|
||||||
kPNGSignatureData = [NSData dataWithBytes:kPNGSignatureBytes length:8];
|
kPNGSignatureData = [NSData dataWithBytes:kPNGSignatureBytes length:8];
|
||||||
});
|
});
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)init
|
- (id)init {
|
||||||
{
|
|
||||||
return [self initWithNamespace:@"default"];
|
return [self initWithNamespace:@"default"];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithNamespace:(NSString *)ns
|
- (id)initWithNamespace:(NSString *)ns {
|
||||||
{
|
if ((self = [super init])) {
|
||||||
if ((self = [super init]))
|
|
||||||
{
|
|
||||||
NSString *fullNamespace = [@"com.hackemist.SDWebImageCache." stringByAppendingString:ns];
|
NSString *fullNamespace = [@"com.hackemist.SDWebImageCache." stringByAppendingString:ns];
|
||||||
|
|
||||||
// Create IO serial queue
|
// Create IO serial queue
|
||||||
|
@ -85,8 +75,7 @@ BOOL ImageDataHasPNGPreffix(NSData *data)
|
||||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
|
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
|
||||||
_diskCachePath = [paths[0] stringByAppendingPathComponent:fullNamespace];
|
_diskCachePath = [paths[0] stringByAppendingPathComponent:fullNamespace];
|
||||||
|
|
||||||
dispatch_sync(_ioQueue, ^
|
dispatch_sync(_ioQueue, ^{
|
||||||
{
|
|
||||||
_fileManager = NSFileManager.new;
|
_fileManager = NSFileManager.new;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -112,72 +101,59 @@ BOOL ImageDataHasPNGPreffix(NSData *data)
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)dealloc
|
- (void)dealloc {
|
||||||
{
|
|
||||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||||
SDDispatchQueueRelease(_ioQueue);
|
SDDispatchQueueRelease(_ioQueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)addReadOnlyCachePath:(NSString *)path
|
- (void)addReadOnlyCachePath:(NSString *)path {
|
||||||
{
|
if (!self.customPaths) {
|
||||||
if (!self.customPaths)
|
|
||||||
{
|
|
||||||
self.customPaths = NSMutableArray.new;
|
self.customPaths = NSMutableArray.new;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (![self.customPaths containsObject:path])
|
if (![self.customPaths containsObject:path]) {
|
||||||
{
|
|
||||||
[self.customPaths addObject:path];
|
[self.customPaths addObject:path];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark SDImageCache (private)
|
#pragma mark SDImageCache (private)
|
||||||
|
|
||||||
- (NSString *)cachePathForKey:(NSString *)key inPath:(NSString *)path
|
- (NSString *)cachePathForKey:(NSString *)key inPath:(NSString *)path {
|
||||||
{
|
|
||||||
NSString *filename = [self cachedFileNameForKey:key];
|
NSString *filename = [self cachedFileNameForKey:key];
|
||||||
return [path stringByAppendingPathComponent:filename];
|
return [path stringByAppendingPathComponent:filename];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *)defaultCachePathForKey:(NSString *)key
|
- (NSString *)defaultCachePathForKey:(NSString *)key {
|
||||||
{
|
|
||||||
return [self cachePathForKey:key inPath:self.diskCachePath];
|
return [self cachePathForKey:key inPath:self.diskCachePath];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *)cachedFileNameForKey:(NSString *)key
|
- (NSString *)cachedFileNameForKey:(NSString *)key {
|
||||||
{
|
|
||||||
const char *str = [key UTF8String];
|
const char *str = [key UTF8String];
|
||||||
if (str == NULL)
|
if (str == NULL) {
|
||||||
{
|
|
||||||
str = "";
|
str = "";
|
||||||
}
|
}
|
||||||
unsigned char r[CC_MD5_DIGEST_LENGTH];
|
unsigned char r[CC_MD5_DIGEST_LENGTH];
|
||||||
CC_MD5(str, (CC_LONG)strlen(str), r);
|
CC_MD5(str, (CC_LONG)strlen(str), r);
|
||||||
NSString *filename = [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
NSString *filename = [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
||||||
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]];
|
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]];
|
||||||
|
|
||||||
return filename;
|
return filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark ImageCache
|
#pragma mark ImageCache
|
||||||
|
|
||||||
- (void)storeImage:(UIImage *)image recalculateFromImage:(BOOL)recalculate imageData:(NSData *)imageData forKey:(NSString *)key toDisk:(BOOL)toDisk
|
- (void)storeImage:(UIImage *)image recalculateFromImage:(BOOL)recalculate imageData:(NSData *)imageData forKey:(NSString *)key toDisk:(BOOL)toDisk {
|
||||||
{
|
if (!image || !key) {
|
||||||
if (!image || !key)
|
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self.memCache setObject:image forKey:key cost:image.size.height * image.size.width * image.scale];
|
[self.memCache setObject:image forKey:key cost:image.size.height * image.size.width * image.scale];
|
||||||
|
|
||||||
if (toDisk)
|
if (toDisk) {
|
||||||
{
|
dispatch_async(self.ioQueue, ^{
|
||||||
dispatch_async(self.ioQueue, ^
|
|
||||||
{
|
|
||||||
NSData *data = imageData;
|
NSData *data = imageData;
|
||||||
|
|
||||||
if (image && (recalculate || !data))
|
if (image && (recalculate || !data)) {
|
||||||
{
|
|
||||||
#if TARGET_OS_IPHONE
|
#if TARGET_OS_IPHONE
|
||||||
// We need to determine if the image is a PNG or a JPEG
|
// 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)
|
// PNGs are easier to detect because they have a unique signature (http://www.w3.org/TR/PNG-Structure.html)
|
||||||
|
@ -189,17 +165,14 @@ BOOL ImageDataHasPNGPreffix(NSData *data)
|
||||||
BOOL imageIsPng = YES;
|
BOOL imageIsPng = YES;
|
||||||
|
|
||||||
// But if we have an image data, we will look at the preffix
|
// But if we have an image data, we will look at the preffix
|
||||||
if ([imageData length] >= [kPNGSignatureData length])
|
if ([imageData length] >= [kPNGSignatureData length]) {
|
||||||
{
|
|
||||||
imageIsPng = ImageDataHasPNGPreffix(imageData);
|
imageIsPng = ImageDataHasPNGPreffix(imageData);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (imageIsPng)
|
if (imageIsPng) {
|
||||||
{
|
|
||||||
data = UIImagePNGRepresentation(image);
|
data = UIImagePNGRepresentation(image);
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
data = UIImageJPEGRepresentation(image, (CGFloat)1.0);
|
data = UIImageJPEGRepresentation(image, (CGFloat)1.0);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
@ -207,13 +180,11 @@ BOOL ImageDataHasPNGPreffix(NSData *data)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data)
|
if (data) {
|
||||||
{
|
|
||||||
// Can't use defaultManager another thread
|
// Can't use defaultManager another thread
|
||||||
NSFileManager *fileManager = NSFileManager.new;
|
NSFileManager *fileManager = NSFileManager.new;
|
||||||
|
|
||||||
if (![fileManager fileExistsAtPath:_diskCachePath])
|
if (![fileManager fileExistsAtPath:_diskCachePath]) {
|
||||||
{
|
|
||||||
[fileManager createDirectoryAtPath:_diskCachePath withIntermediateDirectories:YES attributes:nil error:NULL];
|
[fileManager createDirectoryAtPath:_diskCachePath withIntermediateDirectories:YES attributes:nil error:NULL];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,45 +194,37 @@ BOOL ImageDataHasPNGPreffix(NSData *data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)storeImage:(UIImage *)image forKey:(NSString *)key
|
- (void)storeImage:(UIImage *)image forKey:(NSString *)key {
|
||||||
{
|
|
||||||
[self storeImage:image recalculateFromImage:YES imageData:nil forKey:key toDisk:YES];
|
[self storeImage:image recalculateFromImage:YES imageData:nil forKey:key toDisk:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)storeImage:(UIImage *)image forKey:(NSString *)key toDisk:(BOOL)toDisk
|
- (void)storeImage:(UIImage *)image forKey:(NSString *)key toDisk:(BOOL)toDisk {
|
||||||
{
|
|
||||||
[self storeImage:image recalculateFromImage:YES imageData:nil forKey:key toDisk:toDisk];
|
[self storeImage:image recalculateFromImage:YES imageData:nil forKey:key toDisk:toDisk];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)diskImageExistsWithKey:(NSString *)key
|
- (BOOL)diskImageExistsWithKey:(NSString *)key {
|
||||||
{
|
|
||||||
__block BOOL exists = NO;
|
__block BOOL exists = NO;
|
||||||
dispatch_sync(_ioQueue, ^
|
dispatch_sync(_ioQueue, ^{
|
||||||
{
|
|
||||||
exists = [_fileManager fileExistsAtPath:[self defaultCachePathForKey:key]];
|
exists = [_fileManager fileExistsAtPath:[self defaultCachePathForKey:key]];
|
||||||
});
|
});
|
||||||
|
|
||||||
return exists;
|
return exists;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (UIImage *)imageFromMemoryCacheForKey:(NSString *)key
|
- (UIImage *)imageFromMemoryCacheForKey:(NSString *)key {
|
||||||
{
|
|
||||||
return [self.memCache objectForKey:key];
|
return [self.memCache objectForKey:key];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (UIImage *)imageFromDiskCacheForKey:(NSString *)key
|
- (UIImage *)imageFromDiskCacheForKey:(NSString *)key {
|
||||||
{
|
|
||||||
// First check the in-memory cache...
|
// First check the in-memory cache...
|
||||||
UIImage *image = [self imageFromMemoryCacheForKey:key];
|
UIImage *image = [self imageFromMemoryCacheForKey:key];
|
||||||
if (image)
|
if (image) {
|
||||||
{
|
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Second check the disk cache...
|
// Second check the disk cache...
|
||||||
UIImage *diskImage = [self diskImageForKey:key];
|
UIImage *diskImage = [self diskImageForKey:key];
|
||||||
if (diskImage)
|
if (diskImage) {
|
||||||
{
|
|
||||||
CGFloat cost = diskImage.size.height * diskImage.size.width * diskImage.scale;
|
CGFloat cost = diskImage.size.height * diskImage.size.width * diskImage.scale;
|
||||||
[self.memCache setObject:diskImage forKey:key cost:cost];
|
[self.memCache setObject:diskImage forKey:key cost:cost];
|
||||||
}
|
}
|
||||||
|
@ -269,17 +232,14 @@ BOOL ImageDataHasPNGPreffix(NSData *data)
|
||||||
return diskImage;
|
return diskImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSData *)diskImageDataBySearchingAllPathsForKey:(NSString *)key
|
- (NSData *)diskImageDataBySearchingAllPathsForKey:(NSString *)key {
|
||||||
{
|
|
||||||
NSString *defaultPath = [self defaultCachePathForKey:key];
|
NSString *defaultPath = [self defaultCachePathForKey:key];
|
||||||
NSData *data = [NSData dataWithContentsOfFile:defaultPath];
|
NSData *data = [NSData dataWithContentsOfFile:defaultPath];
|
||||||
if (data)
|
if (data) {
|
||||||
{
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (NSString *path in self.customPaths)
|
for (NSString *path in self.customPaths) {
|
||||||
{
|
|
||||||
NSString *filePath = [self cachePathForKey:key inPath:path];
|
NSString *filePath = [self cachePathForKey:key inPath:path];
|
||||||
NSData *imageData = [NSData dataWithContentsOfFile:filePath];
|
NSData *imageData = [NSData dataWithContentsOfFile:filePath];
|
||||||
if (imageData) {
|
if (imageData) {
|
||||||
|
@ -290,65 +250,53 @@ BOOL ImageDataHasPNGPreffix(NSData *data)
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (UIImage *)diskImageForKey:(NSString *)key
|
- (UIImage *)diskImageForKey:(NSString *)key {
|
||||||
{
|
|
||||||
NSData *data = [self diskImageDataBySearchingAllPathsForKey:key];
|
NSData *data = [self diskImageDataBySearchingAllPathsForKey:key];
|
||||||
if (data)
|
if (data) {
|
||||||
{
|
|
||||||
UIImage *image = [UIImage sd_imageWithData:data];
|
UIImage *image = [UIImage sd_imageWithData:data];
|
||||||
image = [self scaledImageForKey:key image:image];
|
image = [self scaledImageForKey:key image:image];
|
||||||
image = [UIImage decodedImageWithImage:image];
|
image = [UIImage decodedImageWithImage:image];
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (UIImage *)scaledImageForKey:(NSString *)key image:(UIImage *)image
|
- (UIImage *)scaledImageForKey:(NSString *)key image:(UIImage *)image {
|
||||||
{
|
|
||||||
return SDScaledImageForKey(key, image);
|
return SDScaledImageForKey(key, image);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSOperation *)queryDiskCacheForKey:(NSString *)key done:(void (^)(UIImage *image, SDImageCacheType cacheType))doneBlock
|
- (NSOperation *)queryDiskCacheForKey:(NSString *)key done:(void (^)(UIImage *image, SDImageCacheType cacheType))doneBlock {
|
||||||
{
|
|
||||||
NSOperation *operation = NSOperation.new;
|
NSOperation *operation = NSOperation.new;
|
||||||
|
|
||||||
if (!doneBlock) return nil;
|
if (!doneBlock) return nil;
|
||||||
|
|
||||||
if (!key)
|
if (!key) {
|
||||||
{
|
|
||||||
doneBlock(nil, SDImageCacheTypeNone);
|
doneBlock(nil, SDImageCacheTypeNone);
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
// First check the in-memory cache...
|
// First check the in-memory cache...
|
||||||
UIImage *image = [self imageFromMemoryCacheForKey:key];
|
UIImage *image = [self imageFromMemoryCacheForKey:key];
|
||||||
if (image)
|
if (image) {
|
||||||
{
|
|
||||||
doneBlock(image, SDImageCacheTypeMemory);
|
doneBlock(image, SDImageCacheTypeMemory);
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch_async(self.ioQueue, ^
|
dispatch_async(self.ioQueue, ^{
|
||||||
{
|
if (operation.isCancelled) {
|
||||||
if (operation.isCancelled)
|
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@autoreleasepool
|
@autoreleasepool {
|
||||||
{
|
|
||||||
UIImage *diskImage = [self diskImageForKey:key];
|
UIImage *diskImage = [self diskImageForKey:key];
|
||||||
if (diskImage)
|
if (diskImage) {
|
||||||
{
|
|
||||||
CGFloat cost = diskImage.size.height * diskImage.size.width * diskImage.scale;
|
CGFloat cost = diskImage.size.height * diskImage.size.width * diskImage.scale;
|
||||||
[self.memCache setObject:diskImage forKey:key cost:cost];
|
[self.memCache setObject:diskImage forKey:key cost:cost];
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch_main_sync_safe(^
|
dispatch_main_sync_safe(^{
|
||||||
{
|
|
||||||
doneBlock(diskImage, SDImageCacheTypeDisk);
|
doneBlock(diskImage, SDImageCacheTypeDisk);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -357,48 +305,38 @@ BOOL ImageDataHasPNGPreffix(NSData *data)
|
||||||
return operation;
|
return operation;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)removeImageForKey:(NSString *)key
|
- (void)removeImageForKey:(NSString *)key {
|
||||||
{
|
|
||||||
[self removeImageForKey:key fromDisk:YES];
|
[self removeImageForKey:key fromDisk:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)removeImageForKey:(NSString *)key fromDisk:(BOOL)fromDisk
|
- (void)removeImageForKey:(NSString *)key fromDisk:(BOOL)fromDisk {
|
||||||
{
|
if (key == nil) {
|
||||||
if (key == nil)
|
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self.memCache removeObjectForKey:key];
|
[self.memCache removeObjectForKey:key];
|
||||||
|
|
||||||
if (fromDisk)
|
if (fromDisk) {
|
||||||
{
|
dispatch_async(self.ioQueue, ^{
|
||||||
dispatch_async(self.ioQueue, ^
|
|
||||||
{
|
|
||||||
[[NSFileManager defaultManager] removeItemAtPath:[self defaultCachePathForKey:key] error:nil];
|
[[NSFileManager defaultManager] removeItemAtPath:[self defaultCachePathForKey:key] error:nil];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setMaxMemoryCost:(NSUInteger)maxMemoryCost
|
- (void)setMaxMemoryCost:(NSUInteger)maxMemoryCost {
|
||||||
{
|
|
||||||
self.memCache.totalCostLimit = maxMemoryCost;
|
self.memCache.totalCostLimit = maxMemoryCost;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSUInteger)maxMemoryCost
|
- (NSUInteger)maxMemoryCost {
|
||||||
{
|
|
||||||
return self.memCache.totalCostLimit;
|
return self.memCache.totalCostLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)clearMemory
|
- (void)clearMemory {
|
||||||
{
|
|
||||||
[self.memCache removeAllObjects];
|
[self.memCache removeAllObjects];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)clearDisk
|
- (void)clearDisk {
|
||||||
{
|
dispatch_async(self.ioQueue, ^{
|
||||||
dispatch_async(self.ioQueue, ^
|
|
||||||
{
|
|
||||||
[[NSFileManager defaultManager] removeItemAtPath:self.diskCachePath error:nil];
|
[[NSFileManager defaultManager] removeItemAtPath:self.diskCachePath error:nil];
|
||||||
[[NSFileManager defaultManager] createDirectoryAtPath:self.diskCachePath
|
[[NSFileManager defaultManager] createDirectoryAtPath:self.diskCachePath
|
||||||
withIntermediateDirectories:YES
|
withIntermediateDirectories:YES
|
||||||
|
@ -407,13 +345,11 @@ BOOL ImageDataHasPNGPreffix(NSData *data)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)cleanDisk
|
- (void)cleanDisk {
|
||||||
{
|
dispatch_async(self.ioQueue, ^{
|
||||||
dispatch_async(self.ioQueue, ^
|
|
||||||
{
|
|
||||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||||
NSURL *diskCacheURL = [NSURL fileURLWithPath:self.diskCachePath isDirectory:YES];
|
NSURL *diskCacheURL = [NSURL fileURLWithPath:self.diskCachePath isDirectory:YES];
|
||||||
NSArray *resourceKeys = @[ NSURLIsDirectoryKey, NSURLContentModificationDateKey, NSURLTotalFileAllocatedSizeKey ];
|
NSArray *resourceKeys = @[NSURLIsDirectoryKey, NSURLContentModificationDateKey, NSURLTotalFileAllocatedSizeKey];
|
||||||
|
|
||||||
// This enumerator prefetches useful properties for our cache files.
|
// This enumerator prefetches useful properties for our cache files.
|
||||||
NSDirectoryEnumerator *fileEnumerator = [fileManager enumeratorAtURL:diskCacheURL
|
NSDirectoryEnumerator *fileEnumerator = [fileManager enumeratorAtURL:diskCacheURL
|
||||||
|
@ -429,20 +365,17 @@ BOOL ImageDataHasPNGPreffix(NSData *data)
|
||||||
//
|
//
|
||||||
// 1. Removing files that are older than the expiration date.
|
// 1. Removing files that are older than the expiration date.
|
||||||
// 2. Storing file attributes for the size-based cleanup pass.
|
// 2. Storing file attributes for the size-based cleanup pass.
|
||||||
for (NSURL *fileURL in fileEnumerator)
|
for (NSURL *fileURL in fileEnumerator) {
|
||||||
{
|
|
||||||
NSDictionary *resourceValues = [fileURL resourceValuesForKeys:resourceKeys error:NULL];
|
NSDictionary *resourceValues = [fileURL resourceValuesForKeys:resourceKeys error:NULL];
|
||||||
|
|
||||||
// Skip directories.
|
// Skip directories.
|
||||||
if ([resourceValues[NSURLIsDirectoryKey] boolValue])
|
if ([resourceValues[NSURLIsDirectoryKey] boolValue]) {
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove files that are older than the expiration date;
|
// Remove files that are older than the expiration date;
|
||||||
NSDate *modificationDate = resourceValues[NSURLContentModificationDateKey];
|
NSDate *modificationDate = resourceValues[NSURLContentModificationDateKey];
|
||||||
if ([[modificationDate laterDate:expirationDate] isEqualToDate:expirationDate])
|
if ([[modificationDate laterDate:expirationDate] isEqualToDate:expirationDate]) {
|
||||||
{
|
|
||||||
[fileManager removeItemAtURL:fileURL error:nil];
|
[fileManager removeItemAtURL:fileURL error:nil];
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -455,29 +388,24 @@ BOOL ImageDataHasPNGPreffix(NSData *data)
|
||||||
|
|
||||||
// If our remaining disk cache exceeds a configured maximum size, perform a second
|
// If our remaining disk cache exceeds a configured maximum size, perform a second
|
||||||
// size-based cleanup pass. We delete the oldest files first.
|
// size-based cleanup pass. We delete the oldest files first.
|
||||||
if (self.maxCacheSize > 0 && currentCacheSize > self.maxCacheSize)
|
if (self.maxCacheSize > 0 && currentCacheSize > self.maxCacheSize) {
|
||||||
{
|
|
||||||
// Target half of our maximum cache size for this cleanup pass.
|
// Target half of our maximum cache size for this cleanup pass.
|
||||||
const NSUInteger desiredCacheSize = self.maxCacheSize / 2;
|
const NSUInteger desiredCacheSize = self.maxCacheSize / 2;
|
||||||
|
|
||||||
// Sort the remaining cache files by their last modification time (oldest first).
|
// Sort the remaining cache files by their last modification time (oldest first).
|
||||||
NSArray *sortedFiles = [cacheFiles keysSortedByValueWithOptions:NSSortConcurrent
|
NSArray *sortedFiles = [cacheFiles keysSortedByValueWithOptions:NSSortConcurrent
|
||||||
usingComparator:^NSComparisonResult(id obj1, id obj2)
|
usingComparator:^NSComparisonResult(id obj1, id obj2) {
|
||||||
{
|
return [obj1[NSURLContentModificationDateKey] compare:obj2[NSURLContentModificationDateKey]];
|
||||||
return [obj1[NSURLContentModificationDateKey] compare:obj2[NSURLContentModificationDateKey]];
|
}];
|
||||||
}];
|
|
||||||
|
|
||||||
// Delete files until we fall below our desired cache size.
|
// Delete files until we fall below our desired cache size.
|
||||||
for (NSURL *fileURL in sortedFiles)
|
for (NSURL *fileURL in sortedFiles) {
|
||||||
{
|
if ([fileManager removeItemAtURL:fileURL error:nil]) {
|
||||||
if ([fileManager removeItemAtURL:fileURL error:nil])
|
|
||||||
{
|
|
||||||
NSDictionary *resourceValues = cacheFiles[fileURL];
|
NSDictionary *resourceValues = cacheFiles[fileURL];
|
||||||
NSNumber *totalAllocatedSize = resourceValues[NSURLTotalFileAllocatedSizeKey];
|
NSNumber *totalAllocatedSize = resourceValues[NSURLTotalFileAllocatedSizeKey];
|
||||||
currentCacheSize -= [totalAllocatedSize unsignedIntegerValue];
|
currentCacheSize -= [totalAllocatedSize unsignedIntegerValue];
|
||||||
|
|
||||||
if (currentCacheSize < desiredCacheSize)
|
if (currentCacheSize < desiredCacheSize) {
|
||||||
{
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -486,11 +414,9 @@ BOOL ImageDataHasPNGPreffix(NSData *data)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)backgroundCleanDisk
|
- (void)backgroundCleanDisk {
|
||||||
{
|
|
||||||
UIApplication *application = [UIApplication sharedApplication];
|
UIApplication *application = [UIApplication sharedApplication];
|
||||||
__block UIBackgroundTaskIdentifier bgTask = [application beginBackgroundTaskWithExpirationHandler:^
|
__block UIBackgroundTaskIdentifier bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
|
||||||
{
|
|
||||||
// Clean up any unfinished task business by marking where you
|
// Clean up any unfinished task business by marking where you
|
||||||
// stopped or ending the task outright.
|
// stopped or ending the task outright.
|
||||||
[application endBackgroundTask:bgTask];
|
[application endBackgroundTask:bgTask];
|
||||||
|
@ -498,8 +424,7 @@ BOOL ImageDataHasPNGPreffix(NSData *data)
|
||||||
}];
|
}];
|
||||||
|
|
||||||
// Start the long-running task and return immediately.
|
// Start the long-running task and return immediately.
|
||||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||||
{
|
|
||||||
// Do the work associated with the task, preferably in chunks.
|
// Do the work associated with the task, preferably in chunks.
|
||||||
[self cleanDisk];
|
[self cleanDisk];
|
||||||
|
|
||||||
|
@ -508,12 +433,10 @@ BOOL ImageDataHasPNGPreffix(NSData *data)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSUInteger)getSize
|
- (NSUInteger)getSize {
|
||||||
{
|
|
||||||
NSUInteger size = 0;
|
NSUInteger size = 0;
|
||||||
NSDirectoryEnumerator *fileEnumerator = [[NSFileManager defaultManager] enumeratorAtPath:self.diskCachePath];
|
NSDirectoryEnumerator *fileEnumerator = [[NSFileManager defaultManager] enumeratorAtPath:self.diskCachePath];
|
||||||
for (NSString *fileName in fileEnumerator)
|
for (NSString *fileName in fileEnumerator) {
|
||||||
{
|
|
||||||
NSString *filePath = [self.diskCachePath stringByAppendingPathComponent:fileName];
|
NSString *filePath = [self.diskCachePath stringByAppendingPathComponent:fileName];
|
||||||
NSDictionary *attrs = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil];
|
NSDictionary *attrs = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil];
|
||||||
size += [attrs fileSize];
|
size += [attrs fileSize];
|
||||||
|
@ -521,45 +444,38 @@ BOOL ImageDataHasPNGPreffix(NSData *data)
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (int)getDiskCount
|
- (int)getDiskCount {
|
||||||
{
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
NSDirectoryEnumerator *fileEnumerator = [[NSFileManager defaultManager] enumeratorAtPath:self.diskCachePath];
|
NSDirectoryEnumerator *fileEnumerator = [[NSFileManager defaultManager] enumeratorAtPath:self.diskCachePath];
|
||||||
for (__unused NSString *fileName in fileEnumerator)
|
for (__unused NSString *fileName in fileEnumerator) {
|
||||||
{
|
|
||||||
count += 1;
|
count += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)calculateSizeWithCompletionBlock:(void (^)(NSUInteger fileCount, NSUInteger totalSize))completionBlock
|
- (void)calculateSizeWithCompletionBlock:(void (^)(NSUInteger fileCount, NSUInteger totalSize))completionBlock {
|
||||||
{
|
|
||||||
NSURL *diskCacheURL = [NSURL fileURLWithPath:self.diskCachePath isDirectory:YES];
|
NSURL *diskCacheURL = [NSURL fileURLWithPath:self.diskCachePath isDirectory:YES];
|
||||||
|
|
||||||
dispatch_async(self.ioQueue, ^
|
dispatch_async(self.ioQueue, ^{
|
||||||
{
|
|
||||||
NSUInteger fileCount = 0;
|
NSUInteger fileCount = 0;
|
||||||
NSUInteger totalSize = 0;
|
NSUInteger totalSize = 0;
|
||||||
|
|
||||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||||
NSDirectoryEnumerator *fileEnumerator = [fileManager enumeratorAtURL:diskCacheURL
|
NSDirectoryEnumerator *fileEnumerator = [fileManager enumeratorAtURL:diskCacheURL
|
||||||
includingPropertiesForKeys:@[ NSFileSize ]
|
includingPropertiesForKeys:@[NSFileSize]
|
||||||
options:NSDirectoryEnumerationSkipsHiddenFiles
|
options:NSDirectoryEnumerationSkipsHiddenFiles
|
||||||
errorHandler:NULL];
|
errorHandler:NULL];
|
||||||
|
|
||||||
for (NSURL *fileURL in fileEnumerator)
|
for (NSURL *fileURL in fileEnumerator) {
|
||||||
{
|
|
||||||
NSNumber *fileSize;
|
NSNumber *fileSize;
|
||||||
[fileURL getResourceValue:&fileSize forKey:NSURLFileSizeKey error:NULL];
|
[fileURL getResourceValue:&fileSize forKey:NSURLFileSizeKey error:NULL];
|
||||||
totalSize += [fileSize unsignedIntegerValue];
|
totalSize += [fileSize unsignedIntegerValue];
|
||||||
fileCount += 1;
|
fileCount += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (completionBlock)
|
if (completionBlock) {
|
||||||
{
|
dispatch_main_sync_safe(^{
|
||||||
dispatch_main_sync_safe(^
|
|
||||||
{
|
|
||||||
completionBlock(fileCount, totalSize);
|
completionBlock(fileCount, totalSize);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,9 @@
|
||||||
#define UIImageView NSImageView
|
#define UIImageView NSImageView
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if OS_OBJECT_USE_OBJC
|
#if OS_OBJECT_USE_OBJC
|
||||||
|
@ -35,10 +37,10 @@
|
||||||
#define SDDispatchQueueRelease(q)
|
#define SDDispatchQueueRelease(q)
|
||||||
#define SDDispatchQueueSetterSementics strong
|
#define SDDispatchQueueSetterSementics strong
|
||||||
#else
|
#else
|
||||||
#undef SDDispatchQueueRelease
|
#undef SDDispatchQueueRelease
|
||||||
#undef SDDispatchQueueSetterSementics
|
#undef SDDispatchQueueSetterSementics
|
||||||
#define SDDispatchQueueRelease(q) (dispatch_release(q))
|
#define SDDispatchQueueRelease(q) (dispatch_release(q))
|
||||||
#define SDDispatchQueueSetterSementics assign
|
#define SDDispatchQueueSetterSementics assign
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern UIImage *SDScaledImageForKey(NSString *key, UIImage *image);
|
extern UIImage *SDScaledImageForKey(NSString *key, UIImage *image);
|
||||||
|
|
|
@ -12,34 +12,27 @@
|
||||||
#error SDWebImage is ARC only. Either turn on ARC for the project or use -fobjc-arc flag
|
#error SDWebImage is ARC only. Either turn on ARC for the project or use -fobjc-arc flag
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
inline UIImage *SDScaledImageForKey(NSString *key, UIImage *image)
|
inline UIImage *SDScaledImageForKey(NSString *key, UIImage *image) {
|
||||||
{
|
if ([image.images count] > 0) {
|
||||||
if ([image.images count] > 0)
|
|
||||||
{
|
|
||||||
NSMutableArray *scaledImages = [NSMutableArray array];
|
NSMutableArray *scaledImages = [NSMutableArray array];
|
||||||
|
|
||||||
for (UIImage *tempImage in image.images)
|
for (UIImage *tempImage in image.images) {
|
||||||
{
|
|
||||||
[scaledImages addObject:SDScaledImageForKey(key, tempImage)];
|
[scaledImages addObject:SDScaledImageForKey(key, tempImage)];
|
||||||
}
|
}
|
||||||
|
|
||||||
return [UIImage animatedImageWithImages:scaledImages duration:image.duration];
|
return [UIImage animatedImageWithImages:scaledImages duration:image.duration];
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) {
|
||||||
if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)])
|
|
||||||
{
|
|
||||||
CGFloat scale = 1.0;
|
CGFloat scale = 1.0;
|
||||||
if (key.length >= 8)
|
if (key.length >= 8) {
|
||||||
{
|
|
||||||
// Search @2x. at the end of the string, before a 3 to 4 extension length (only if key len is 8 or more @2x. + 4 len ext)
|
// Search @2x. at the end of the string, before a 3 to 4 extension length (only if key len is 8 or more @2x. + 4 len ext)
|
||||||
NSRange range = [key rangeOfString:@"@2x." options:0 range:NSMakeRange(key.length - 8, 5)];
|
NSRange range = [key rangeOfString:@"@2x." options:0 range:NSMakeRange(key.length - 8, 5)];
|
||||||
if (range.location != NSNotFound)
|
if (range.location != NSNotFound) {
|
||||||
{
|
|
||||||
scale = 2.0;
|
scale = 2.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UIImage *scaledImage = [[UIImage alloc] initWithCGImage:image.CGImage scale:scale orientation:image.imageOrientation];
|
UIImage *scaledImage = [[UIImage alloc] initWithCGImage:image.CGImage scale:scale orientation:image.imageOrientation];
|
||||||
image = scaledImage;
|
image = scaledImage;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,10 +12,8 @@
|
||||||
|
|
||||||
@implementation UIImage (ForceDecode)
|
@implementation UIImage (ForceDecode)
|
||||||
|
|
||||||
+ (UIImage *)decodedImageWithImage:(UIImage *)image
|
+ (UIImage *)decodedImageWithImage:(UIImage *)image {
|
||||||
{
|
if (image.images) {
|
||||||
if (image.images)
|
|
||||||
{
|
|
||||||
// Do not decode animated images
|
// Do not decode animated images
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
@ -29,22 +27,20 @@
|
||||||
|
|
||||||
int infoMask = (bitmapInfo & kCGBitmapAlphaInfoMask);
|
int infoMask = (bitmapInfo & kCGBitmapAlphaInfoMask);
|
||||||
BOOL anyNonAlpha = (infoMask == kCGImageAlphaNone ||
|
BOOL anyNonAlpha = (infoMask == kCGImageAlphaNone ||
|
||||||
infoMask == kCGImageAlphaNoneSkipFirst ||
|
infoMask == kCGImageAlphaNoneSkipFirst ||
|
||||||
infoMask == kCGImageAlphaNoneSkipLast);
|
infoMask == kCGImageAlphaNoneSkipLast);
|
||||||
|
|
||||||
// CGBitmapContextCreate doesn't support kCGImageAlphaNone with RGB.
|
// CGBitmapContextCreate doesn't support kCGImageAlphaNone with RGB.
|
||||||
// https://developer.apple.com/library/mac/#qa/qa1037/_index.html
|
// https://developer.apple.com/library/mac/#qa/qa1037/_index.html
|
||||||
if (infoMask == kCGImageAlphaNone && CGColorSpaceGetNumberOfComponents(colorSpace) > 1)
|
if (infoMask == kCGImageAlphaNone && CGColorSpaceGetNumberOfComponents(colorSpace) > 1) {
|
||||||
{
|
|
||||||
// Unset the old alpha info.
|
// Unset the old alpha info.
|
||||||
bitmapInfo &= ~kCGBitmapAlphaInfoMask;
|
bitmapInfo &= ~kCGBitmapAlphaInfoMask;
|
||||||
|
|
||||||
// Set noneSkipFirst.
|
// Set noneSkipFirst.
|
||||||
bitmapInfo |= kCGImageAlphaNoneSkipFirst;
|
bitmapInfo |= kCGImageAlphaNoneSkipFirst;
|
||||||
}
|
}
|
||||||
// Some PNGs tell us they have alpha but only 3 components. Odd.
|
// Some PNGs tell us they have alpha but only 3 components. Odd.
|
||||||
else if (!anyNonAlpha && CGColorSpaceGetNumberOfComponents(colorSpace) == 3)
|
else if (!anyNonAlpha && CGColorSpaceGetNumberOfComponents(colorSpace) == 3) {
|
||||||
{
|
|
||||||
// Unset the old alpha info.
|
// Unset the old alpha info.
|
||||||
bitmapInfo &= ~kCGBitmapAlphaInfoMask;
|
bitmapInfo &= ~kCGBitmapAlphaInfoMask;
|
||||||
bitmapInfo |= kCGImageAlphaPremultipliedFirst;
|
bitmapInfo |= kCGImageAlphaPremultipliedFirst;
|
||||||
|
@ -52,22 +48,22 @@
|
||||||
|
|
||||||
// It calculates the bytes-per-row based on the bitsPerComponent and width arguments.
|
// It calculates the bytes-per-row based on the bitsPerComponent and width arguments.
|
||||||
CGContextRef context = CGBitmapContextCreate(NULL,
|
CGContextRef context = CGBitmapContextCreate(NULL,
|
||||||
imageSize.width,
|
imageSize.width,
|
||||||
imageSize.height,
|
imageSize.height,
|
||||||
CGImageGetBitsPerComponent(imageRef),
|
CGImageGetBitsPerComponent(imageRef),
|
||||||
0,
|
0,
|
||||||
colorSpace,
|
colorSpace,
|
||||||
bitmapInfo);
|
bitmapInfo);
|
||||||
CGColorSpaceRelease(colorSpace);
|
CGColorSpaceRelease(colorSpace);
|
||||||
|
|
||||||
// If failed, return undecompressed image
|
// If failed, return undecompressed image
|
||||||
if (!context) return image;
|
if (!context) return image;
|
||||||
|
|
||||||
CGContextDrawImage(context, imageRect, imageRef);
|
CGContextDrawImage(context, imageRect, imageRef);
|
||||||
CGImageRef decompressedImageRef = CGBitmapContextCreateImage(context);
|
CGImageRef decompressedImageRef = CGBitmapContextCreateImage(context);
|
||||||
|
|
||||||
CGContextRelease(context);
|
CGContextRelease(context);
|
||||||
|
|
||||||
UIImage *decompressedImage = [UIImage imageWithCGImage:decompressedImageRef scale:image.scale orientation:image.imageOrientation];
|
UIImage *decompressedImage = [UIImage imageWithCGImage:decompressedImageRef scale:image.scale orientation:image.imageOrientation];
|
||||||
CGImageRelease(decompressedImageRef);
|
CGImageRelease(decompressedImageRef);
|
||||||
return decompressedImage;
|
return decompressedImage;
|
||||||
|
|
|
@ -10,45 +10,43 @@
|
||||||
#import "SDWebImageCompat.h"
|
#import "SDWebImageCompat.h"
|
||||||
#import "SDWebImageOperation.h"
|
#import "SDWebImageOperation.h"
|
||||||
|
|
||||||
typedef enum
|
typedef enum {
|
||||||
{
|
|
||||||
SDWebImageDownloaderLowPriority = 1 << 0,
|
SDWebImageDownloaderLowPriority = 1 << 0,
|
||||||
SDWebImageDownloaderProgressiveDownload = 1 << 1,
|
SDWebImageDownloaderProgressiveDownload = 1 << 1,
|
||||||
/**
|
/**
|
||||||
* By default, request prevent the of NSURLCache. With this flag, NSURLCache
|
* By default, request prevent the of NSURLCache. With this flag, NSURLCache
|
||||||
* is used with default policies.
|
* is used with default policies.
|
||||||
*/
|
*/
|
||||||
SDWebImageDownloaderUseNSURLCache = 1 << 2,
|
SDWebImageDownloaderUseNSURLCache = 1 << 2,
|
||||||
/**
|
/**
|
||||||
* Call completion block with nil image/imageData if the image was read from NSURLCache
|
* Call completion block with nil image/imageData if the image was read from NSURLCache
|
||||||
* (to be combined with `SDWebImageDownloaderUseNSURLCache`).
|
* (to be combined with `SDWebImageDownloaderUseNSURLCache`).
|
||||||
*/
|
*/
|
||||||
SDWebImageDownloaderIgnoreCachedResponse = 1 << 3,
|
SDWebImageDownloaderIgnoreCachedResponse = 1 << 3,
|
||||||
/**
|
/**
|
||||||
* In iOS 4+, continue the download of the image if the app goes to background. This is achieved by asking the system for
|
* In iOS 4+, continue the download of the image if the app goes to background. This is achieved by asking the system for
|
||||||
* extra time in background to let the request finish. If the background task expires the operation will be cancelled.
|
* extra time in background to let the request finish. If the background task expires the operation will be cancelled.
|
||||||
*/
|
*/
|
||||||
SDWebImageDownloaderContinueInBackground = 1 << 4,
|
SDWebImageDownloaderContinueInBackground = 1 << 4,
|
||||||
/**
|
/**
|
||||||
* Handles cookies stored in NSHTTPCookieStore by setting
|
* Handles cookies stored in NSHTTPCookieStore by setting
|
||||||
* NSMutableURLRequest.HTTPShouldHandleCookies = YES;
|
* NSMutableURLRequest.HTTPShouldHandleCookies = YES;
|
||||||
*/
|
*/
|
||||||
SDWebImageDownloaderHandleCookies = 1 << 5,
|
SDWebImageDownloaderHandleCookies = 1 << 5,
|
||||||
/**
|
/**
|
||||||
* Enable to allow untrusted SSL ceriticates.
|
* Enable to allow untrusted SSL ceriticates.
|
||||||
* Useful for testing purposes. Use with caution in production.
|
* Useful for testing purposes. Use with caution in production.
|
||||||
*/
|
*/
|
||||||
SDWebImageDownloaderAllowInvalidSSLCertificates = 1 << 6
|
SDWebImageDownloaderAllowInvalidSSLCertificates = 1 << 6
|
||||||
|
|
||||||
} SDWebImageDownloaderOptions;
|
} SDWebImageDownloaderOptions;
|
||||||
|
|
||||||
typedef enum
|
typedef enum {
|
||||||
{
|
|
||||||
SDWebImageDownloaderFIFOExecutionOrder,
|
SDWebImageDownloaderFIFOExecutionOrder,
|
||||||
/**
|
/**
|
||||||
* Default value. All download operations will execute in queue style (first-in-first-out).
|
* Default value. All download operations will execute in queue style (first-in-first-out).
|
||||||
*/
|
*/
|
||||||
SDWebImageDownloaderLIFOExecutionOrder
|
SDWebImageDownloaderLIFOExecutionOrder
|
||||||
/**
|
/**
|
||||||
* All download operations will execute in stack style (last-in-first-out).
|
* All download operations will execute in stack style (last-in-first-out).
|
||||||
*/
|
*/
|
||||||
|
@ -58,6 +56,7 @@ extern NSString *const SDWebImageDownloadStartNotification;
|
||||||
extern NSString *const SDWebImageDownloadStopNotification;
|
extern NSString *const SDWebImageDownloadStopNotification;
|
||||||
|
|
||||||
typedef void(^SDWebImageDownloaderProgressBlock)(NSInteger receivedSize, NSInteger expectedSize);
|
typedef void(^SDWebImageDownloaderProgressBlock)(NSInteger receivedSize, NSInteger expectedSize);
|
||||||
|
|
||||||
typedef void(^SDWebImageDownloaderCompletedBlock)(UIImage *image, NSData *data, NSError *error, BOOL finished);
|
typedef void(^SDWebImageDownloaderCompletedBlock)(UIImage *image, NSData *data, NSError *error, BOOL finished);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -131,9 +130,9 @@ typedef void(^SDWebImageDownloaderCompletedBlock)(UIImage *image, NSData *data,
|
||||||
*
|
*
|
||||||
* @return A cancellable SDWebImageOperation
|
* @return A cancellable SDWebImageOperation
|
||||||
*/
|
*/
|
||||||
- (id<SDWebImageOperation>)downloadImageWithURL:(NSURL *)url
|
- (id <SDWebImageOperation>)downloadImageWithURL:(NSURL *)url
|
||||||
options:(SDWebImageDownloaderOptions)options
|
options:(SDWebImageDownloaderOptions)options
|
||||||
progress:(SDWebImageDownloaderProgressBlock)progressBlock
|
progress:(SDWebImageDownloaderProgressBlock)progressBlock
|
||||||
completed:(SDWebImageDownloaderCompletedBlock)completedBlock;
|
completed:(SDWebImageDownloaderCompletedBlock)completedBlock;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -29,12 +29,10 @@ static NSString *const kCompletedCallbackKey = @"completed";
|
||||||
|
|
||||||
@implementation SDWebImageDownloader
|
@implementation SDWebImageDownloader
|
||||||
|
|
||||||
+ (void)initialize
|
+ (void)initialize {
|
||||||
{
|
|
||||||
// Bind SDNetworkActivityIndicator if available (download it here: http://github.com/rs/SDNetworkActivityIndicator )
|
// Bind SDNetworkActivityIndicator if available (download it here: http://github.com/rs/SDNetworkActivityIndicator )
|
||||||
// To use it, just add #import "SDNetworkActivityIndicator.h" in addition to the SDWebImage import
|
// To use it, just add #import "SDNetworkActivityIndicator.h" in addition to the SDWebImage import
|
||||||
if (NSClassFromString(@"SDNetworkActivityIndicator"))
|
if (NSClassFromString(@"SDNetworkActivityIndicator")) {
|
||||||
{
|
|
||||||
|
|
||||||
#pragma clang diagnostic push
|
#pragma clang diagnostic push
|
||||||
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
|
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
|
||||||
|
@ -54,18 +52,17 @@ static NSString *const kCompletedCallbackKey = @"completed";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (SDWebImageDownloader *)sharedDownloader
|
+ (SDWebImageDownloader *)sharedDownloader {
|
||||||
{
|
|
||||||
static dispatch_once_t once;
|
static dispatch_once_t once;
|
||||||
static id instance;
|
static id instance;
|
||||||
dispatch_once(&once, ^{instance = self.new;});
|
dispatch_once(&once, ^{
|
||||||
|
instance = self.new;
|
||||||
|
});
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)init
|
- (id)init {
|
||||||
{
|
if ((self = [super init])) {
|
||||||
if ((self = [super init]))
|
|
||||||
{
|
|
||||||
_executionOrder = SDWebImageDownloaderFIFOExecutionOrder;
|
_executionOrder = SDWebImageDownloaderFIFOExecutionOrder;
|
||||||
_downloadQueue = NSOperationQueue.new;
|
_downloadQueue = NSOperationQueue.new;
|
||||||
_downloadQueue.maxConcurrentOperationCount = 2;
|
_downloadQueue.maxConcurrentOperationCount = 2;
|
||||||
|
@ -77,103 +74,84 @@ static NSString *const kCompletedCallbackKey = @"completed";
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)dealloc
|
- (void)dealloc {
|
||||||
{
|
|
||||||
[self.downloadQueue cancelAllOperations];
|
[self.downloadQueue cancelAllOperations];
|
||||||
SDDispatchQueueRelease(_barrierQueue);
|
SDDispatchQueueRelease(_barrierQueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setValue:(NSString *)value forHTTPHeaderField:(NSString *)field
|
- (void)setValue:(NSString *)value forHTTPHeaderField:(NSString *)field {
|
||||||
{
|
if (value) {
|
||||||
if (value)
|
|
||||||
{
|
|
||||||
self.HTTPHeaders[field] = value;
|
self.HTTPHeaders[field] = value;
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
[self.HTTPHeaders removeObjectForKey:field];
|
[self.HTTPHeaders removeObjectForKey:field];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *)valueForHTTPHeaderField:(NSString *)field
|
- (NSString *)valueForHTTPHeaderField:(NSString *)field {
|
||||||
{
|
|
||||||
return self.HTTPHeaders[field];
|
return self.HTTPHeaders[field];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setMaxConcurrentDownloads:(NSInteger)maxConcurrentDownloads
|
- (void)setMaxConcurrentDownloads:(NSInteger)maxConcurrentDownloads {
|
||||||
{
|
|
||||||
_downloadQueue.maxConcurrentOperationCount = maxConcurrentDownloads;
|
_downloadQueue.maxConcurrentOperationCount = maxConcurrentDownloads;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSUInteger)currentDownloadCount
|
- (NSUInteger)currentDownloadCount {
|
||||||
{
|
|
||||||
return _downloadQueue.operationCount;
|
return _downloadQueue.operationCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSInteger)maxConcurrentDownloads
|
- (NSInteger)maxConcurrentDownloads {
|
||||||
{
|
|
||||||
return _downloadQueue.maxConcurrentOperationCount;
|
return _downloadQueue.maxConcurrentOperationCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id<SDWebImageOperation>)downloadImageWithURL:(NSURL *)url options:(SDWebImageDownloaderOptions)options progress:(void (^)(NSInteger, NSInteger))progressBlock completed:(void (^)(UIImage *, NSData *, NSError *, BOOL))completedBlock
|
- (id <SDWebImageOperation>)downloadImageWithURL:(NSURL *)url options:(SDWebImageDownloaderOptions)options progress:(void (^)(NSInteger, NSInteger))progressBlock completed:(void (^)(UIImage *, NSData *, NSError *, BOOL))completedBlock {
|
||||||
{
|
|
||||||
__block SDWebImageDownloaderOperation *operation;
|
__block SDWebImageDownloaderOperation *operation;
|
||||||
__weak SDWebImageDownloader *wself = self;
|
__weak SDWebImageDownloader *wself = self;
|
||||||
|
|
||||||
[self addProgressCallback:progressBlock andCompletedBlock:completedBlock forURL:url createCallback:^
|
[self addProgressCallback:progressBlock andCompletedBlock:completedBlock forURL:url createCallback:^{
|
||||||
{
|
|
||||||
NSTimeInterval timeoutInterval = wself.downloadTimeout;
|
NSTimeInterval timeoutInterval = wself.downloadTimeout;
|
||||||
if (timeoutInterval == 0.0) {
|
if (timeoutInterval == 0.0) {
|
||||||
timeoutInterval = 15.0;
|
timeoutInterval = 15.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// In order to prevent from potential duplicate caching (NSURLCache + SDImageCache) we disable the cache for image requests if told otherwise
|
// In order to prevent from potential duplicate caching (NSURLCache + SDImageCache) we disable the cache for image requests if told otherwise
|
||||||
NSMutableURLRequest *request = [NSMutableURLRequest.alloc initWithURL:url cachePolicy:(options & SDWebImageDownloaderUseNSURLCache ? NSURLRequestUseProtocolCachePolicy : NSURLRequestReloadIgnoringLocalCacheData) timeoutInterval:timeoutInterval];
|
NSMutableURLRequest *request = [NSMutableURLRequest.alloc initWithURL:url cachePolicy:(options & SDWebImageDownloaderUseNSURLCache ? NSURLRequestUseProtocolCachePolicy : NSURLRequestReloadIgnoringLocalCacheData) timeoutInterval:timeoutInterval];
|
||||||
request.HTTPShouldHandleCookies = (options & SDWebImageDownloaderHandleCookies);
|
request.HTTPShouldHandleCookies = (options & SDWebImageDownloaderHandleCookies);
|
||||||
request.HTTPShouldUsePipelining = YES;
|
request.HTTPShouldUsePipelining = YES;
|
||||||
if (wself.headersFilter)
|
if (wself.headersFilter) {
|
||||||
{
|
|
||||||
request.allHTTPHeaderFields = wself.headersFilter(url, [wself.HTTPHeaders copy]);
|
request.allHTTPHeaderFields = wself.headersFilter(url, [wself.HTTPHeaders copy]);
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
request.allHTTPHeaderFields = wself.HTTPHeaders;
|
request.allHTTPHeaderFields = wself.HTTPHeaders;
|
||||||
}
|
}
|
||||||
operation = [SDWebImageDownloaderOperation.alloc initWithRequest:request options:options progress:^(NSInteger receivedSize, NSInteger expectedSize)
|
operation = [SDWebImageDownloaderOperation.alloc initWithRequest:request options:options progress:^(NSInteger receivedSize, NSInteger expectedSize) {
|
||||||
{
|
|
||||||
if (!wself) return;
|
if (!wself) return;
|
||||||
SDWebImageDownloader *sself = wself;
|
SDWebImageDownloader *sself = wself;
|
||||||
NSArray *callbacksForURL = [sself callbacksForURL:url];
|
NSArray *callbacksForURL = [sself callbacksForURL:url];
|
||||||
for (NSDictionary *callbacks in callbacksForURL)
|
for (NSDictionary *callbacks in callbacksForURL) {
|
||||||
{
|
|
||||||
SDWebImageDownloaderProgressBlock callback = callbacks[kProgressCallbackKey];
|
SDWebImageDownloaderProgressBlock callback = callbacks[kProgressCallbackKey];
|
||||||
if (callback) callback(receivedSize, expectedSize);
|
if (callback) callback(receivedSize, expectedSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished)
|
completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) {
|
||||||
{
|
if (!wself) return;
|
||||||
if (!wself) return;
|
SDWebImageDownloader *sself = wself;
|
||||||
SDWebImageDownloader *sself = wself;
|
NSArray *callbacksForURL = [sself callbacksForURL:url];
|
||||||
NSArray *callbacksForURL = [sself callbacksForURL:url];
|
if (finished) {
|
||||||
if (finished)
|
[sself removeCallbacksForURL:url];
|
||||||
{
|
}
|
||||||
[sself removeCallbacksForURL:url];
|
for (NSDictionary *callbacks in callbacksForURL) {
|
||||||
}
|
SDWebImageDownloaderCompletedBlock callback = callbacks[kCompletedCallbackKey];
|
||||||
for (NSDictionary *callbacks in callbacksForURL)
|
if (callback) callback(image, data, error, finished);
|
||||||
{
|
}
|
||||||
SDWebImageDownloaderCompletedBlock callback = callbacks[kCompletedCallbackKey];
|
}
|
||||||
if (callback) callback(image, data, error, finished);
|
cancelled:^{
|
||||||
}
|
if (!wself) return;
|
||||||
}
|
SDWebImageDownloader *sself = wself;
|
||||||
cancelled:^
|
[sself removeCallbacksForURL:url];
|
||||||
{
|
}];
|
||||||
if (!wself) return;
|
|
||||||
SDWebImageDownloader *sself = wself;
|
|
||||||
[sself removeCallbacksForURL:url];
|
|
||||||
}];
|
|
||||||
[wself.downloadQueue addOperation:operation];
|
[wself.downloadQueue addOperation:operation];
|
||||||
if (wself.executionOrder == SDWebImageDownloaderLIFOExecutionOrder)
|
if (wself.executionOrder == SDWebImageDownloaderLIFOExecutionOrder) {
|
||||||
{
|
|
||||||
// Emulate LIFO execution order by systematically adding new operations as last operation's dependency
|
// Emulate LIFO execution order by systematically adding new operations as last operation's dependency
|
||||||
[wself.lastAddedOperation addDependency:operation];
|
[wself.lastAddedOperation addDependency:operation];
|
||||||
wself.lastAddedOperation = operation;
|
wself.lastAddedOperation = operation;
|
||||||
|
@ -183,23 +161,18 @@ static NSString *const kCompletedCallbackKey = @"completed";
|
||||||
return operation;
|
return operation;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)addProgressCallback:(void (^)(NSInteger, NSInteger))progressBlock andCompletedBlock:(void (^)(UIImage *, NSData *data, NSError *, BOOL))completedBlock forURL:(NSURL *)url createCallback:(void (^)())createCallback
|
- (void)addProgressCallback:(void (^)(NSInteger, NSInteger))progressBlock andCompletedBlock:(void (^)(UIImage *, NSData *data, NSError *, BOOL))completedBlock forURL:(NSURL *)url createCallback:(void (^)())createCallback {
|
||||||
{
|
|
||||||
// The URL will be used as the key to the callbacks dictionary so it cannot be nil. If it is nil immediately call the completed block with no image or data.
|
// The URL will be used as the key to the callbacks dictionary so it cannot be nil. If it is nil immediately call the completed block with no image or data.
|
||||||
if(url == nil)
|
if (url == nil) {
|
||||||
{
|
if (completedBlock != nil) {
|
||||||
if (completedBlock != nil)
|
|
||||||
{
|
|
||||||
completedBlock(nil, nil, nil, NO);
|
completedBlock(nil, nil, nil, NO);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch_barrier_sync(self.barrierQueue, ^
|
dispatch_barrier_sync(self.barrierQueue, ^{
|
||||||
{
|
|
||||||
BOOL first = NO;
|
BOOL first = NO;
|
||||||
if (!self.URLCallbacks[url])
|
if (!self.URLCallbacks[url]) {
|
||||||
{
|
|
||||||
self.URLCallbacks[url] = NSMutableArray.new;
|
self.URLCallbacks[url] = NSMutableArray.new;
|
||||||
first = YES;
|
first = YES;
|
||||||
}
|
}
|
||||||
|
@ -212,27 +185,22 @@ static NSString *const kCompletedCallbackKey = @"completed";
|
||||||
[callbacksForURL addObject:callbacks];
|
[callbacksForURL addObject:callbacks];
|
||||||
self.URLCallbacks[url] = callbacksForURL;
|
self.URLCallbacks[url] = callbacksForURL;
|
||||||
|
|
||||||
if (first)
|
if (first) {
|
||||||
{
|
|
||||||
createCallback();
|
createCallback();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSArray *)callbacksForURL:(NSURL *)url
|
- (NSArray *)callbacksForURL:(NSURL *)url {
|
||||||
{
|
|
||||||
__block NSArray *callbacksForURL;
|
__block NSArray *callbacksForURL;
|
||||||
dispatch_sync(self.barrierQueue, ^
|
dispatch_sync(self.barrierQueue, ^{
|
||||||
{
|
|
||||||
callbacksForURL = self.URLCallbacks[url];
|
callbacksForURL = self.URLCallbacks[url];
|
||||||
});
|
});
|
||||||
return [callbacksForURL copy];
|
return [callbacksForURL copy];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)removeCallbacksForURL:(NSURL *)url
|
- (void)removeCallbacksForURL:(NSURL *)url {
|
||||||
{
|
dispatch_barrier_async(self.barrierQueue, ^{
|
||||||
dispatch_barrier_async(self.barrierQueue, ^
|
|
||||||
{
|
|
||||||
[self.URLCallbacks removeObjectForKey:url];
|
[self.URLCallbacks removeObjectForKey:url];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,16 +30,13 @@
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation SDWebImageDownloaderOperation
|
@implementation SDWebImageDownloaderOperation {
|
||||||
{
|
|
||||||
size_t width, height;
|
size_t width, height;
|
||||||
BOOL responseFromCached;
|
BOOL responseFromCached;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithRequest:(NSURLRequest *)request options:(SDWebImageDownloaderOptions)options progress:(void (^)(NSInteger, NSInteger))progressBlock completed:(void (^)(UIImage *, NSData *, NSError *, BOOL))completedBlock cancelled:(void (^)())cancelBlock
|
- (id)initWithRequest:(NSURLRequest *)request options:(SDWebImageDownloaderOptions)options progress:(void (^)(NSInteger, NSInteger))progressBlock completed:(void (^)(UIImage *, NSData *, NSError *, BOOL))completedBlock cancelled:(void (^)())cancelBlock {
|
||||||
{
|
if ((self = [super init])) {
|
||||||
if ((self = [super init]))
|
|
||||||
{
|
|
||||||
_request = request;
|
_request = request;
|
||||||
_options = options;
|
_options = options;
|
||||||
_progressBlock = [progressBlock copy];
|
_progressBlock = [progressBlock copy];
|
||||||
|
@ -53,27 +50,21 @@
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)start
|
- (void)start {
|
||||||
{
|
@synchronized (self) {
|
||||||
@synchronized(self)
|
if (self.isCancelled) {
|
||||||
{
|
|
||||||
if (self.isCancelled)
|
|
||||||
{
|
|
||||||
self.finished = YES;
|
self.finished = YES;
|
||||||
[self reset];
|
[self reset];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_4_0
|
#if TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_4_0
|
||||||
if ([self shouldContinueWhenAppEntersBackground])
|
if ([self shouldContinueWhenAppEntersBackground]) {
|
||||||
{
|
__weak __typeof__ (self) wself = self;
|
||||||
__weak __typeof__(self) wself = self;
|
self.backgroundTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
|
||||||
self.backgroundTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^
|
__strong __typeof (wself) sself = wself;
|
||||||
{
|
|
||||||
__strong __typeof(wself)sself = wself;
|
|
||||||
|
|
||||||
if (sself)
|
if (sself) {
|
||||||
{
|
|
||||||
[sself cancel];
|
[sself cancel];
|
||||||
|
|
||||||
[[UIApplication sharedApplication] endBackgroundTask:sself.backgroundTaskId];
|
[[UIApplication sharedApplication] endBackgroundTask:sself.backgroundTaskId];
|
||||||
|
@ -90,70 +81,56 @@
|
||||||
|
|
||||||
[self.connection start];
|
[self.connection start];
|
||||||
|
|
||||||
if (self.connection)
|
if (self.connection) {
|
||||||
{
|
if (self.progressBlock) {
|
||||||
if (self.progressBlock)
|
|
||||||
{
|
|
||||||
self.progressBlock(0, NSURLResponseUnknownLength);
|
self.progressBlock(0, NSURLResponseUnknownLength);
|
||||||
}
|
}
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStartNotification object:self];
|
[[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStartNotification object:self];
|
||||||
|
|
||||||
if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_5_1)
|
if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_5_1) {
|
||||||
{
|
|
||||||
// Make sure to run the runloop in our background thread so it can process downloaded data
|
// Make sure to run the runloop in our background thread so it can process downloaded data
|
||||||
// Note: we use a timeout to work around an issue with NSURLConnection cancel under iOS 5
|
// Note: we use a timeout to work around an issue with NSURLConnection cancel under iOS 5
|
||||||
// not waking up the runloop, leading to dead threads (see https://github.com/rs/SDWebImage/issues/466)
|
// not waking up the runloop, leading to dead threads (see https://github.com/rs/SDWebImage/issues/466)
|
||||||
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 10, false);
|
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 10, false);
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
CFRunLoopRun();
|
CFRunLoopRun();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!self.isFinished)
|
if (!self.isFinished) {
|
||||||
{
|
|
||||||
[self.connection cancel];
|
[self.connection cancel];
|
||||||
[self connection:self.connection didFailWithError:[NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorTimedOut userInfo:@{NSURLErrorFailingURLErrorKey: self.request.URL}]];
|
[self connection:self.connection didFailWithError:[NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorTimedOut userInfo:@{NSURLErrorFailingURLErrorKey : self.request.URL}]];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
if (self.completedBlock) {
|
||||||
if (self.completedBlock)
|
self.completedBlock(nil, nil, [NSError errorWithDomain:NSURLErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey : @"Connection can't be initialized"}], YES);
|
||||||
{
|
|
||||||
self.completedBlock(nil, nil, [NSError errorWithDomain:NSURLErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey: @"Connection can't be initialized"}], YES);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)cancel
|
- (void)cancel {
|
||||||
{
|
@synchronized (self) {
|
||||||
@synchronized(self)
|
if (self.thread) {
|
||||||
{
|
|
||||||
if (self.thread)
|
|
||||||
{
|
|
||||||
[self performSelector:@selector(cancelInternalAndStop) onThread:self.thread withObject:nil waitUntilDone:NO];
|
[self performSelector:@selector(cancelInternalAndStop) onThread:self.thread withObject:nil waitUntilDone:NO];
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
[self cancelInternal];
|
[self cancelInternal];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)cancelInternalAndStop
|
- (void)cancelInternalAndStop {
|
||||||
{
|
|
||||||
[self cancelInternal];
|
[self cancelInternal];
|
||||||
CFRunLoopStop(CFRunLoopGetCurrent());
|
CFRunLoopStop(CFRunLoopGetCurrent());
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)cancelInternal
|
- (void)cancelInternal {
|
||||||
{
|
|
||||||
if (self.isFinished) return;
|
if (self.isFinished) return;
|
||||||
[super cancel];
|
[super cancel];
|
||||||
if (self.cancelBlock) self.cancelBlock();
|
if (self.cancelBlock) self.cancelBlock();
|
||||||
|
|
||||||
if (self.connection)
|
if (self.connection) {
|
||||||
{
|
|
||||||
[self.connection cancel];
|
[self.connection cancel];
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStopNotification object:self];
|
[[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStopNotification object:self];
|
||||||
|
|
||||||
|
@ -166,15 +143,13 @@
|
||||||
[self reset];
|
[self reset];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)done
|
- (void)done {
|
||||||
{
|
|
||||||
self.finished = YES;
|
self.finished = YES;
|
||||||
self.executing = NO;
|
self.executing = NO;
|
||||||
[self reset];
|
[self reset];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)reset
|
- (void)reset {
|
||||||
{
|
|
||||||
self.cancelBlock = nil;
|
self.cancelBlock = nil;
|
||||||
self.completedBlock = nil;
|
self.completedBlock = nil;
|
||||||
self.progressBlock = nil;
|
self.progressBlock = nil;
|
||||||
|
@ -183,48 +158,40 @@
|
||||||
self.thread = nil;
|
self.thread = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setFinished:(BOOL)finished
|
- (void)setFinished:(BOOL)finished {
|
||||||
{
|
|
||||||
[self willChangeValueForKey:@"isFinished"];
|
[self willChangeValueForKey:@"isFinished"];
|
||||||
_finished = finished;
|
_finished = finished;
|
||||||
[self didChangeValueForKey:@"isFinished"];
|
[self didChangeValueForKey:@"isFinished"];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setExecuting:(BOOL)executing
|
- (void)setExecuting:(BOOL)executing {
|
||||||
{
|
|
||||||
[self willChangeValueForKey:@"isExecuting"];
|
[self willChangeValueForKey:@"isExecuting"];
|
||||||
_executing = executing;
|
_executing = executing;
|
||||||
[self didChangeValueForKey:@"isExecuting"];
|
[self didChangeValueForKey:@"isExecuting"];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)isConcurrent
|
- (BOOL)isConcurrent {
|
||||||
{
|
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark NSURLConnection (delegate)
|
#pragma mark NSURLConnection (delegate)
|
||||||
|
|
||||||
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
|
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
|
||||||
{
|
if (![response respondsToSelector:@selector(statusCode)] || [((NSHTTPURLResponse *)response) statusCode] < 400) {
|
||||||
if (![response respondsToSelector:@selector(statusCode)] || [((NSHTTPURLResponse *)response) statusCode] < 400)
|
|
||||||
{
|
|
||||||
NSInteger expected = response.expectedContentLength > 0 ? (NSInteger)response.expectedContentLength : 0;
|
NSInteger expected = response.expectedContentLength > 0 ? (NSInteger)response.expectedContentLength : 0;
|
||||||
self.expectedSize = expected;
|
self.expectedSize = expected;
|
||||||
if (self.progressBlock)
|
if (self.progressBlock) {
|
||||||
{
|
|
||||||
self.progressBlock(0, expected);
|
self.progressBlock(0, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.imageData = [NSMutableData.alloc initWithCapacity:expected];
|
self.imageData = [NSMutableData.alloc initWithCapacity:expected];
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
[self.connection cancel];
|
[self.connection cancel];
|
||||||
|
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStopNotification object:nil];
|
[[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStopNotification object:nil];
|
||||||
|
|
||||||
if (self.completedBlock)
|
if (self.completedBlock) {
|
||||||
{
|
|
||||||
self.completedBlock(nil, nil, [NSError errorWithDomain:NSURLErrorDomain code:[((NSHTTPURLResponse *)response) statusCode] userInfo:nil], YES);
|
self.completedBlock(nil, nil, [NSError errorWithDomain:NSURLErrorDomain code:[((NSHTTPURLResponse *)response) statusCode] userInfo:nil], YES);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,12 +199,10 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
|
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
|
||||||
{
|
|
||||||
[self.imageData appendData:data];
|
[self.imageData appendData:data];
|
||||||
|
|
||||||
if ((self.options & SDWebImageDownloaderProgressiveDownload) && self.expectedSize > 0 && self.completedBlock)
|
if ((self.options & SDWebImageDownloaderProgressiveDownload) && self.expectedSize > 0 && self.completedBlock) {
|
||||||
{
|
|
||||||
// The following code is from http://www.cocoaintheshell.com/2011/05/progressive-images-download-imageio/
|
// The following code is from http://www.cocoaintheshell.com/2011/05/progressive-images-download-imageio/
|
||||||
// Thanks to the author @Nyx0uf
|
// Thanks to the author @Nyx0uf
|
||||||
|
|
||||||
|
@ -246,13 +211,11 @@
|
||||||
|
|
||||||
// Update the data source, we must pass ALL the data, not just the new bytes
|
// Update the data source, we must pass ALL the data, not just the new bytes
|
||||||
CGImageSourceRef imageSource = CGImageSourceCreateIncremental(NULL);
|
CGImageSourceRef imageSource = CGImageSourceCreateIncremental(NULL);
|
||||||
CGImageSourceUpdateData(imageSource, (__bridge CFDataRef)self.imageData, totalSize == self.expectedSize);
|
CGImageSourceUpdateData(imageSource, (__bridge CFDataRef)self.imageData, totalSize == self.expectedSize);
|
||||||
|
|
||||||
if (width + height == 0)
|
if (width + height == 0) {
|
||||||
{
|
|
||||||
CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, NULL);
|
CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, NULL);
|
||||||
if (properties)
|
if (properties) {
|
||||||
{
|
|
||||||
CFTypeRef val = CFDictionaryGetValue(properties, kCGImagePropertyPixelHeight);
|
CFTypeRef val = CFDictionaryGetValue(properties, kCGImagePropertyPixelHeight);
|
||||||
if (val) CFNumberGetValue(val, kCFNumberLongType, &height);
|
if (val) CFNumberGetValue(val, kCFNumberLongType, &height);
|
||||||
val = CFDictionaryGetValue(properties, kCGImagePropertyPixelWidth);
|
val = CFDictionaryGetValue(properties, kCGImagePropertyPixelWidth);
|
||||||
|
@ -261,44 +224,37 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (width + height > 0 && totalSize < self.expectedSize)
|
if (width + height > 0 && totalSize < self.expectedSize) {
|
||||||
{
|
|
||||||
// Create the image
|
// Create the image
|
||||||
CGImageRef partialImageRef = CGImageSourceCreateImageAtIndex(imageSource, 0, NULL);
|
CGImageRef partialImageRef = CGImageSourceCreateImageAtIndex(imageSource, 0, NULL);
|
||||||
|
|
||||||
#ifdef TARGET_OS_IPHONE
|
#ifdef TARGET_OS_IPHONE
|
||||||
// Workaround for iOS anamorphic image
|
// Workaround for iOS anamorphic image
|
||||||
if (partialImageRef)
|
if (partialImageRef) {
|
||||||
{
|
|
||||||
const size_t partialHeight = CGImageGetHeight(partialImageRef);
|
const size_t partialHeight = CGImageGetHeight(partialImageRef);
|
||||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||||
CGContextRef bmContext = CGBitmapContextCreate(NULL, width, height, 8, width * 4, colorSpace, kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst);
|
CGContextRef bmContext = CGBitmapContextCreate(NULL, width, height, 8, width * 4, colorSpace, kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst);
|
||||||
CGColorSpaceRelease(colorSpace);
|
CGColorSpaceRelease(colorSpace);
|
||||||
if (bmContext)
|
if (bmContext) {
|
||||||
{
|
|
||||||
CGContextDrawImage(bmContext, (CGRect){.origin.x = 0.0f, .origin.y = 0.0f, .size.width = width, .size.height = partialHeight}, partialImageRef);
|
CGContextDrawImage(bmContext, (CGRect){.origin.x = 0.0f, .origin.y = 0.0f, .size.width = width, .size.height = partialHeight}, partialImageRef);
|
||||||
CGImageRelease(partialImageRef);
|
CGImageRelease(partialImageRef);
|
||||||
partialImageRef = CGBitmapContextCreateImage(bmContext);
|
partialImageRef = CGBitmapContextCreateImage(bmContext);
|
||||||
CGContextRelease(bmContext);
|
CGContextRelease(bmContext);
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
CGImageRelease(partialImageRef);
|
CGImageRelease(partialImageRef);
|
||||||
partialImageRef = nil;
|
partialImageRef = nil;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (partialImageRef)
|
if (partialImageRef) {
|
||||||
{
|
|
||||||
UIImage *image = [UIImage imageWithCGImage:partialImageRef];
|
UIImage *image = [UIImage imageWithCGImage:partialImageRef];
|
||||||
UIImage *scaledImage = [self scaledImageForKey:self.request.URL.absoluteString image:image];
|
UIImage *scaledImage = [self scaledImageForKey:self.request.URL.absoluteString image:image];
|
||||||
image = [UIImage decodedImageWithImage:scaledImage];
|
image = [UIImage decodedImageWithImage:scaledImage];
|
||||||
CGImageRelease(partialImageRef);
|
CGImageRelease(partialImageRef);
|
||||||
dispatch_main_sync_safe(^
|
dispatch_main_sync_safe(^{
|
||||||
{
|
if (self.completedBlock) {
|
||||||
if (self.completedBlock)
|
|
||||||
{
|
|
||||||
self.completedBlock(image, nil, nil, NO);
|
self.completedBlock(image, nil, nil, NO);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -308,19 +264,16 @@
|
||||||
CFRelease(imageSource);
|
CFRelease(imageSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.progressBlock)
|
if (self.progressBlock) {
|
||||||
{
|
|
||||||
self.progressBlock(self.imageData.length, self.expectedSize);
|
self.progressBlock(self.imageData.length, self.expectedSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (UIImage *)scaledImageForKey:(NSString *)key image:(UIImage *)image
|
- (UIImage *)scaledImageForKey:(NSString *)key image:(UIImage *)image {
|
||||||
{
|
|
||||||
return SDScaledImageForKey(key, image);
|
return SDScaledImageForKey(key, image);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)connectionDidFinishLoading:(NSURLConnection *)aConnection
|
- (void)connectionDidFinishLoading:(NSURLConnection *)aConnection {
|
||||||
{
|
|
||||||
CFRunLoopStop(CFRunLoopGetCurrent());
|
CFRunLoopStop(CFRunLoopGetCurrent());
|
||||||
self.connection = nil;
|
self.connection = nil;
|
||||||
|
|
||||||
|
@ -328,16 +281,13 @@
|
||||||
|
|
||||||
SDWebImageDownloaderCompletedBlock completionBlock = self.completedBlock;
|
SDWebImageDownloaderCompletedBlock completionBlock = self.completedBlock;
|
||||||
|
|
||||||
if (completionBlock)
|
if (completionBlock) {
|
||||||
{
|
if (self.options & SDWebImageDownloaderIgnoreCachedResponse && responseFromCached) {
|
||||||
if (self.options & SDWebImageDownloaderIgnoreCachedResponse && responseFromCached)
|
|
||||||
{
|
|
||||||
completionBlock(nil, nil, nil, YES);
|
completionBlock(nil, nil, nil, YES);
|
||||||
self.completionBlock = nil;
|
self.completionBlock = nil;
|
||||||
[self done];
|
[self done];
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
|
|
||||||
UIImage *image = [UIImage sd_imageWithData:self.imageData];
|
UIImage *image = [UIImage sd_imageWithData:self.imageData];
|
||||||
|
|
||||||
|
@ -348,66 +298,54 @@
|
||||||
image = [UIImage decodedImageWithImage:image];
|
image = [UIImage decodedImageWithImage:image];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CGSizeEqualToSize(image.size, CGSizeZero))
|
if (CGSizeEqualToSize(image.size, CGSizeZero)) {
|
||||||
{
|
completionBlock(nil, nil, [NSError errorWithDomain:@"SDWebImageErrorDomain" code:0 userInfo:@{NSLocalizedDescriptionKey : @"Downloaded image has 0 pixels"}], YES);
|
||||||
completionBlock(nil, nil, [NSError errorWithDomain:@"SDWebImageErrorDomain" code:0 userInfo:@{NSLocalizedDescriptionKey: @"Downloaded image has 0 pixels"}], YES);
|
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
completionBlock(image, self.imageData, nil, YES);
|
completionBlock(image, self.imageData, nil, YES);
|
||||||
}
|
}
|
||||||
self.completionBlock = nil;
|
self.completionBlock = nil;
|
||||||
[self done];
|
[self done];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
[self done];
|
[self done];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
|
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
|
||||||
{
|
|
||||||
CFRunLoopStop(CFRunLoopGetCurrent());
|
CFRunLoopStop(CFRunLoopGetCurrent());
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStopNotification object:nil];
|
[[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStopNotification object:nil];
|
||||||
|
|
||||||
if (self.completedBlock)
|
if (self.completedBlock) {
|
||||||
{
|
|
||||||
self.completedBlock(nil, nil, error, YES);
|
self.completedBlock(nil, nil, error, YES);
|
||||||
}
|
}
|
||||||
|
|
||||||
[self done];
|
[self done];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse
|
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse {
|
||||||
{
|
|
||||||
responseFromCached = NO; // If this method is called, it means the response wasn't read from cache
|
responseFromCached = NO; // If this method is called, it means the response wasn't read from cache
|
||||||
if (self.request.cachePolicy == NSURLRequestReloadIgnoringLocalCacheData)
|
if (self.request.cachePolicy == NSURLRequestReloadIgnoringLocalCacheData) {
|
||||||
{
|
|
||||||
// Prevents caching of responses
|
// Prevents caching of responses
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
return cachedResponse;
|
return cachedResponse;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)shouldContinueWhenAppEntersBackground
|
- (BOOL)shouldContinueWhenAppEntersBackground {
|
||||||
{
|
|
||||||
return self.options & SDWebImageDownloaderContinueInBackground;
|
return self.options & SDWebImageDownloaderContinueInBackground;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
|
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
|
||||||
{
|
|
||||||
return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
|
return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
|
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
|
||||||
{
|
|
||||||
BOOL trustAllCertificates = (self.options & SDWebImageDownloaderAllowInvalidSSLCertificates);
|
BOOL trustAllCertificates = (self.options & SDWebImageDownloaderAllowInvalidSSLCertificates);
|
||||||
if (trustAllCertificates && [challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
|
if (trustAllCertificates && [challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
|
||||||
{
|
|
||||||
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]
|
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]
|
||||||
forAuthenticationChallenge:challenge];
|
forAuthenticationChallenge:challenge];
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,27 +11,26 @@
|
||||||
#import "SDWebImageDownloader.h"
|
#import "SDWebImageDownloader.h"
|
||||||
#import "SDImageCache.h"
|
#import "SDImageCache.h"
|
||||||
|
|
||||||
typedef enum
|
typedef enum {
|
||||||
{
|
|
||||||
/**
|
/**
|
||||||
* By default, when a URL fail to be downloaded, the URL is blacklisted so the library won't keep trying.
|
* By default, when a URL fail to be downloaded, the URL is blacklisted so the library won't keep trying.
|
||||||
* This flag disable this blacklisting.
|
* This flag disable this blacklisting.
|
||||||
*/
|
*/
|
||||||
SDWebImageRetryFailed = 1 << 0,
|
SDWebImageRetryFailed = 1 << 0,
|
||||||
/**
|
/**
|
||||||
* By default, image downloads are started during UI interactions, this flags disable this feature,
|
* By default, image downloads are started during UI interactions, this flags disable this feature,
|
||||||
* leading to delayed download on UIScrollView deceleration for instance.
|
* leading to delayed download on UIScrollView deceleration for instance.
|
||||||
*/
|
*/
|
||||||
SDWebImageLowPriority = 1 << 1,
|
SDWebImageLowPriority = 1 << 1,
|
||||||
/**
|
/**
|
||||||
* This flag disables on-disk caching
|
* This flag disables on-disk caching
|
||||||
*/
|
*/
|
||||||
SDWebImageCacheMemoryOnly = 1 << 2,
|
SDWebImageCacheMemoryOnly = 1 << 2,
|
||||||
/**
|
/**
|
||||||
* This flag enables progressive download, the image is displayed progressively during download as a browser would do.
|
* This flag enables progressive download, the image is displayed progressively during download as a browser would do.
|
||||||
* By default, the image is only displayed once completely downloaded.
|
* By default, the image is only displayed once completely downloaded.
|
||||||
*/
|
*/
|
||||||
SDWebImageProgressiveDownload = 1 << 3,
|
SDWebImageProgressiveDownload = 1 << 3,
|
||||||
/**
|
/**
|
||||||
* Even if the image is cached, respect the HTTP response cache control, and refresh the image from remote location if needed.
|
* Even if the image is cached, respect the HTTP response cache control, and refresh the image from remote location if needed.
|
||||||
* The disk caching will be handled by NSURLCache instead of SDWebImage leading to slight performance degradation.
|
* The disk caching will be handled by NSURLCache instead of SDWebImage leading to slight performance degradation.
|
||||||
|
@ -40,26 +39,27 @@ typedef enum
|
||||||
*
|
*
|
||||||
* Use this flag only if you can't make your URLs static with embeded cache busting parameter.
|
* Use this flag only if you can't make your URLs static with embeded cache busting parameter.
|
||||||
*/
|
*/
|
||||||
SDWebImageRefreshCached = 1 << 4,
|
SDWebImageRefreshCached = 1 << 4,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* In iOS 4+, continue the download of the image if the app goes to background. This is achieved by asking the system for
|
* In iOS 4+, continue the download of the image if the app goes to background. This is achieved by asking the system for
|
||||||
* extra time in background to let the request finish. If the background task expires the operation will be cancelled.
|
* extra time in background to let the request finish. If the background task expires the operation will be cancelled.
|
||||||
*/
|
*/
|
||||||
SDWebImageContinueInBackground = 1 << 5,
|
SDWebImageContinueInBackground = 1 << 5,
|
||||||
/**
|
/**
|
||||||
* Handles cookies stored in NSHTTPCookieStore by setting
|
* Handles cookies stored in NSHTTPCookieStore by setting
|
||||||
* NSMutableURLRequest.HTTPShouldHandleCookies = YES;
|
* NSMutableURLRequest.HTTPShouldHandleCookies = YES;
|
||||||
*/
|
*/
|
||||||
SDWebImageHandleCookies = 1 << 6,
|
SDWebImageHandleCookies = 1 << 6,
|
||||||
/**
|
/**
|
||||||
* Enable to allow untrusted SSL ceriticates.
|
* Enable to allow untrusted SSL ceriticates.
|
||||||
* Useful for testing purposes. Use with caution in production.
|
* Useful for testing purposes. Use with caution in production.
|
||||||
*/
|
*/
|
||||||
SDWebImageAllowInvalidSSLCertificates = 1 << 7
|
SDWebImageAllowInvalidSSLCertificates = 1 << 7
|
||||||
} SDWebImageOptions;
|
} SDWebImageOptions;
|
||||||
|
|
||||||
typedef void(^SDWebImageCompletedBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType);
|
typedef void(^SDWebImageCompletedBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType);
|
||||||
|
|
||||||
typedef void(^SDWebImageCompletedWithFinishedBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished);
|
typedef void(^SDWebImageCompletedWithFinishedBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished);
|
||||||
|
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ SDWebImageManager *manager = [SDWebImageManager sharedManager];
|
||||||
*/
|
*/
|
||||||
@interface SDWebImageManager : NSObject
|
@interface SDWebImageManager : NSObject
|
||||||
|
|
||||||
@property (weak, nonatomic) id<SDWebImageManagerDelegate> delegate;
|
@property (weak, nonatomic) id <SDWebImageManagerDelegate> delegate;
|
||||||
|
|
||||||
@property (strong, nonatomic, readonly) SDImageCache *imageCache;
|
@property (strong, nonatomic, readonly) SDImageCache *imageCache;
|
||||||
@property (strong, nonatomic, readonly) SDWebImageDownloader *imageDownloader;
|
@property (strong, nonatomic, readonly) SDWebImageDownloader *imageDownloader;
|
||||||
|
@ -172,10 +172,10 @@ SDWebImageManager *manager = [SDWebImageManager sharedManager];
|
||||||
*
|
*
|
||||||
* @return Returns a cancellable NSOperation
|
* @return Returns a cancellable NSOperation
|
||||||
*/
|
*/
|
||||||
- (id<SDWebImageOperation>)downloadWithURL:(NSURL *)url
|
- (id <SDWebImageOperation>)downloadWithURL:(NSURL *)url
|
||||||
options:(SDWebImageOptions)options
|
options:(SDWebImageOptions)options
|
||||||
progress:(SDWebImageDownloaderProgressBlock)progressBlock
|
progress:(SDWebImageDownloaderProgressBlock)progressBlock
|
||||||
completed:(SDWebImageCompletedWithFinishedBlock)completedBlock;
|
completed:(SDWebImageCompletedWithFinishedBlock)completedBlock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cancel all current opreations
|
* Cancel all current opreations
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#import "SDWebImageManager.h"
|
#import "SDWebImageManager.h"
|
||||||
#import "UIImage+GIF.h"
|
|
||||||
#import <objc/message.h>
|
#import <objc/message.h>
|
||||||
|
|
||||||
@interface SDWebImageCombinedOperation : NSObject <SDWebImageOperation>
|
@interface SDWebImageCombinedOperation : NSObject <SDWebImageOperation>
|
||||||
|
@ -29,18 +28,17 @@
|
||||||
|
|
||||||
@implementation SDWebImageManager
|
@implementation SDWebImageManager
|
||||||
|
|
||||||
+ (id)sharedManager
|
+ (id)sharedManager {
|
||||||
{
|
|
||||||
static dispatch_once_t once;
|
static dispatch_once_t once;
|
||||||
static id instance;
|
static id instance;
|
||||||
dispatch_once(&once, ^{instance = self.new;});
|
dispatch_once(&once, ^{
|
||||||
|
instance = self.new;
|
||||||
|
});
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)init
|
- (id)init {
|
||||||
{
|
if ((self = [super init])) {
|
||||||
if ((self = [super init]))
|
|
||||||
{
|
|
||||||
_imageCache = [self createCache];
|
_imageCache = [self createCache];
|
||||||
_imageDownloader = SDWebImageDownloader.new;
|
_imageDownloader = SDWebImageDownloader.new;
|
||||||
_failedURLs = NSMutableArray.new;
|
_failedURLs = NSMutableArray.new;
|
||||||
|
@ -49,90 +47,72 @@
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (SDImageCache *)createCache
|
- (SDImageCache *)createCache {
|
||||||
{
|
|
||||||
return [SDImageCache sharedImageCache];
|
return [SDImageCache sharedImageCache];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *)cacheKeyForURL:(NSURL *)url
|
- (NSString *)cacheKeyForURL:(NSURL *)url {
|
||||||
{
|
if (self.cacheKeyFilter) {
|
||||||
if (self.cacheKeyFilter)
|
|
||||||
{
|
|
||||||
return self.cacheKeyFilter(url);
|
return self.cacheKeyFilter(url);
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
return [url absoluteString];
|
return [url absoluteString];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)diskImageExistsForURL:(NSURL *)url
|
- (BOOL)diskImageExistsForURL:(NSURL *)url {
|
||||||
{
|
|
||||||
NSString *key = [self cacheKeyForURL:url];
|
NSString *key = [self cacheKeyForURL:url];
|
||||||
return [self.imageCache diskImageExistsWithKey:key];
|
return [self.imageCache diskImageExistsWithKey:key];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id<SDWebImageOperation>)downloadWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletedWithFinishedBlock)completedBlock
|
- (id <SDWebImageOperation>)downloadWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletedWithFinishedBlock)completedBlock {
|
||||||
{
|
|
||||||
// Invoking this method without a completedBlock is pointless
|
// Invoking this method without a completedBlock is pointless
|
||||||
NSParameterAssert(completedBlock);
|
NSParameterAssert(completedBlock);
|
||||||
|
|
||||||
// Very common mistake is to send the URL using NSString object instead of NSURL. For some strange reason, XCode won't
|
// Very common mistake is to send the URL using NSString object instead of NSURL. For some strange reason, XCode won't
|
||||||
// throw any warning for this type mismatch. Here we failsafe this error by allowing URLs to be passed as NSString.
|
// throw any warning for this type mismatch. Here we failsafe this error by allowing URLs to be passed as NSString.
|
||||||
if ([url isKindOfClass:NSString.class])
|
if ([url isKindOfClass:NSString.class]) {
|
||||||
{
|
|
||||||
url = [NSURL URLWithString:(NSString *)url];
|
url = [NSURL URLWithString:(NSString *)url];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prevents app crashing on argument type error like sending NSNull instead of NSURL
|
// Prevents app crashing on argument type error like sending NSNull instead of NSURL
|
||||||
if (![url isKindOfClass:NSURL.class])
|
if (![url isKindOfClass:NSURL.class]) {
|
||||||
{
|
|
||||||
url = nil;
|
url = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
__block SDWebImageCombinedOperation *operation = SDWebImageCombinedOperation.new;
|
__block SDWebImageCombinedOperation *operation = SDWebImageCombinedOperation.new;
|
||||||
__weak SDWebImageCombinedOperation *weakOperation = operation;
|
__weak SDWebImageCombinedOperation *weakOperation = operation;
|
||||||
|
|
||||||
BOOL isFailedUrl = NO;
|
BOOL isFailedUrl = NO;
|
||||||
@synchronized(self.failedURLs)
|
@synchronized (self.failedURLs) {
|
||||||
{
|
|
||||||
isFailedUrl = [self.failedURLs containsObject:url];
|
isFailedUrl = [self.failedURLs containsObject:url];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!url || (!(options & SDWebImageRetryFailed) && isFailedUrl))
|
if (!url || (!(options & SDWebImageRetryFailed) && isFailedUrl)) {
|
||||||
{
|
dispatch_main_sync_safe(^{
|
||||||
dispatch_main_sync_safe(^
|
NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorFileDoesNotExist userInfo:nil];
|
||||||
{
|
completedBlock(nil, error, SDImageCacheTypeNone, YES);
|
||||||
NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorFileDoesNotExist userInfo:nil];
|
|
||||||
completedBlock(nil, error, SDImageCacheTypeNone, YES);
|
|
||||||
});
|
});
|
||||||
return operation;
|
return operation;
|
||||||
}
|
}
|
||||||
|
|
||||||
@synchronized(self.runningOperations)
|
@synchronized (self.runningOperations) {
|
||||||
{
|
|
||||||
[self.runningOperations addObject:operation];
|
[self.runningOperations addObject:operation];
|
||||||
}
|
}
|
||||||
NSString *key = [self cacheKeyForURL:url];
|
NSString *key = [self cacheKeyForURL:url];
|
||||||
|
|
||||||
operation.cacheOperation = [self.imageCache queryDiskCacheForKey:key done:^(UIImage *image, SDImageCacheType cacheType)
|
operation.cacheOperation = [self.imageCache queryDiskCacheForKey:key done:^(UIImage *image, SDImageCacheType cacheType) {
|
||||||
{
|
if (operation.isCancelled) {
|
||||||
if (operation.isCancelled)
|
@synchronized (self.runningOperations) {
|
||||||
{
|
|
||||||
@synchronized(self.runningOperations)
|
|
||||||
{
|
|
||||||
[self.runningOperations removeObject:operation];
|
[self.runningOperations removeObject:operation];
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((!image || options & SDWebImageRefreshCached) && (![self.delegate respondsToSelector:@selector(imageManager:shouldDownloadImageForURL:)] || [self.delegate imageManager:self shouldDownloadImageForURL:url]))
|
if ((!image || options & SDWebImageRefreshCached) && (![self.delegate respondsToSelector:@selector(imageManager:shouldDownloadImageForURL:)] || [self.delegate imageManager:self shouldDownloadImageForURL:url])) {
|
||||||
{
|
if (image && options & SDWebImageRefreshCached) {
|
||||||
if (image && options & SDWebImageRefreshCached)
|
dispatch_main_sync_safe(^{
|
||||||
{
|
|
||||||
dispatch_main_sync_safe(^
|
|
||||||
{
|
|
||||||
// If image was found in the cache bug SDWebImageRefreshCached is provided, notify about the cached image
|
// 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.
|
// AND try to re-download it in order to let a chance to NSURLCache to refresh it from server.
|
||||||
completedBlock(image, nil, cacheType, YES);
|
completedBlock(image, nil, cacheType, YES);
|
||||||
|
@ -147,108 +127,85 @@
|
||||||
if (options & SDWebImageContinueInBackground) downloaderOptions |= SDWebImageDownloaderContinueInBackground;
|
if (options & SDWebImageContinueInBackground) downloaderOptions |= SDWebImageDownloaderContinueInBackground;
|
||||||
if (options & SDWebImageHandleCookies) downloaderOptions |= SDWebImageDownloaderHandleCookies;
|
if (options & SDWebImageHandleCookies) downloaderOptions |= SDWebImageDownloaderHandleCookies;
|
||||||
if (options & SDWebImageAllowInvalidSSLCertificates) downloaderOptions |= SDWebImageDownloaderAllowInvalidSSLCertificates;
|
if (options & SDWebImageAllowInvalidSSLCertificates) downloaderOptions |= SDWebImageDownloaderAllowInvalidSSLCertificates;
|
||||||
if (image && options & SDWebImageRefreshCached)
|
if (image && options & SDWebImageRefreshCached) {
|
||||||
{
|
|
||||||
// force progressive off if image already cached but forced refreshing
|
// force progressive off if image already cached but forced refreshing
|
||||||
downloaderOptions &= ~SDWebImageDownloaderProgressiveDownload;
|
downloaderOptions &= ~SDWebImageDownloaderProgressiveDownload;
|
||||||
// ignore image read from NSURLCache if image if cached but force refreshing
|
// ignore image read from NSURLCache if image if cached but force refreshing
|
||||||
downloaderOptions |= SDWebImageDownloaderIgnoreCachedResponse;
|
downloaderOptions |= SDWebImageDownloaderIgnoreCachedResponse;
|
||||||
}
|
}
|
||||||
id<SDWebImageOperation> subOperation = [self.imageDownloader downloadImageWithURL:url options:downloaderOptions progress:progressBlock completed:^(UIImage *downloadedImage, NSData *data, NSError *error, BOOL finished)
|
id <SDWebImageOperation> subOperation = [self.imageDownloader downloadImageWithURL:url options:downloaderOptions progress:progressBlock completed:^(UIImage *downloadedImage, NSData *data, NSError *error, BOOL finished) {
|
||||||
{
|
if (weakOperation.isCancelled) {
|
||||||
if (weakOperation.isCancelled)
|
dispatch_main_sync_safe(^{
|
||||||
{
|
|
||||||
dispatch_main_sync_safe(^
|
|
||||||
{
|
|
||||||
completedBlock(nil, nil, SDImageCacheTypeNone, finished);
|
completedBlock(nil, nil, SDImageCacheTypeNone, finished);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else if (error)
|
else if (error) {
|
||||||
{
|
dispatch_main_sync_safe(^{
|
||||||
dispatch_main_sync_safe(^
|
|
||||||
{
|
|
||||||
completedBlock(nil, error, SDImageCacheTypeNone, finished);
|
completedBlock(nil, error, SDImageCacheTypeNone, finished);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (error.code != NSURLErrorNotConnectedToInternet)
|
if (error.code != NSURLErrorNotConnectedToInternet) {
|
||||||
{
|
@synchronized (self.failedURLs) {
|
||||||
@synchronized(self.failedURLs)
|
|
||||||
{
|
|
||||||
[self.failedURLs addObject:url];
|
[self.failedURLs addObject:url];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
BOOL cacheOnDisk = !(options & SDWebImageCacheMemoryOnly);
|
BOOL cacheOnDisk = !(options & SDWebImageCacheMemoryOnly);
|
||||||
|
|
||||||
if (options & SDWebImageRefreshCached && image && !downloadedImage)
|
if (options & SDWebImageRefreshCached && image && !downloadedImage) {
|
||||||
{
|
|
||||||
// Image refresh hit the NSURLCache cache, do not call the completion block
|
// Image refresh hit the NSURLCache cache, do not call the completion block
|
||||||
}
|
}
|
||||||
// NOTE: We don't call transformDownloadedImage delegate method on animated images as most transformation code would mangle it
|
// NOTE: We don't call transformDownloadedImage delegate method on animated images as most transformation code would mangle it
|
||||||
else if (downloadedImage && !downloadedImage.images && [self.delegate respondsToSelector:@selector(imageManager:transformDownloadedImage:withURL:)])
|
else if (downloadedImage && !downloadedImage.images && [self.delegate respondsToSelector:@selector(imageManager:transformDownloadedImage:withURL:)]) {
|
||||||
{
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
|
||||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^
|
|
||||||
{
|
|
||||||
UIImage *transformedImage = [self.delegate imageManager:self transformDownloadedImage:downloadedImage withURL:url];
|
UIImage *transformedImage = [self.delegate imageManager:self transformDownloadedImage:downloadedImage withURL:url];
|
||||||
|
|
||||||
dispatch_main_sync_safe(^
|
dispatch_main_sync_safe(^{
|
||||||
{
|
|
||||||
completedBlock(transformedImage, nil, SDImageCacheTypeNone, finished);
|
completedBlock(transformedImage, nil, SDImageCacheTypeNone, finished);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (transformedImage && finished)
|
if (transformedImage && finished) {
|
||||||
{
|
|
||||||
BOOL imageWasTransformed = ![transformedImage isEqual:downloadedImage];
|
BOOL imageWasTransformed = ![transformedImage isEqual:downloadedImage];
|
||||||
[self.imageCache storeImage:transformedImage recalculateFromImage:imageWasTransformed imageData:data forKey:key toDisk:cacheOnDisk];
|
[self.imageCache storeImage:transformedImage recalculateFromImage:imageWasTransformed imageData:data forKey:key toDisk:cacheOnDisk];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
dispatch_main_sync_safe(^{
|
||||||
dispatch_main_sync_safe(^
|
|
||||||
{
|
|
||||||
completedBlock(downloadedImage, nil, SDImageCacheTypeNone, finished);
|
completedBlock(downloadedImage, nil, SDImageCacheTypeNone, finished);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (downloadedImage && finished)
|
if (downloadedImage && finished) {
|
||||||
{
|
|
||||||
[self.imageCache storeImage:downloadedImage recalculateFromImage:NO imageData:data forKey:key toDisk:cacheOnDisk];
|
[self.imageCache storeImage:downloadedImage recalculateFromImage:NO imageData:data forKey:key toDisk:cacheOnDisk];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (finished)
|
if (finished) {
|
||||||
{
|
@synchronized (self.runningOperations) {
|
||||||
@synchronized(self.runningOperations)
|
|
||||||
{
|
|
||||||
[self.runningOperations removeObject:operation];
|
[self.runningOperations removeObject:operation];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
operation.cancelBlock = ^{[subOperation cancel];};
|
operation.cancelBlock = ^{
|
||||||
|
[subOperation cancel];
|
||||||
|
};
|
||||||
}
|
}
|
||||||
else if (image)
|
else if (image) {
|
||||||
{
|
dispatch_main_sync_safe(^{
|
||||||
dispatch_main_sync_safe(^
|
|
||||||
{
|
|
||||||
completedBlock(image, nil, cacheType, YES);
|
completedBlock(image, nil, cacheType, YES);
|
||||||
});
|
});
|
||||||
@synchronized(self.runningOperations)
|
@synchronized (self.runningOperations) {
|
||||||
{
|
|
||||||
[self.runningOperations removeObject:operation];
|
[self.runningOperations removeObject:operation];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
// Image not in cache and download disallowed by delegate
|
// Image not in cache and download disallowed by delegate
|
||||||
dispatch_main_sync_safe(^
|
dispatch_main_sync_safe(^{
|
||||||
{
|
|
||||||
completedBlock(nil, nil, SDImageCacheTypeNone, YES);
|
completedBlock(nil, nil, SDImageCacheTypeNone, YES);
|
||||||
});
|
});
|
||||||
@synchronized(self.runningOperations)
|
@synchronized (self.runningOperations) {
|
||||||
{
|
|
||||||
[self.runningOperations removeObject:operation];
|
[self.runningOperations removeObject:operation];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -257,17 +214,14 @@
|
||||||
return operation;
|
return operation;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)cancelAll
|
- (void)cancelAll {
|
||||||
{
|
@synchronized (self.runningOperations) {
|
||||||
@synchronized(self.runningOperations)
|
|
||||||
{
|
|
||||||
[self.runningOperations makeObjectsPerformSelector:@selector(cancel)];
|
[self.runningOperations makeObjectsPerformSelector:@selector(cancel)];
|
||||||
[self.runningOperations removeAllObjects];
|
[self.runningOperations removeAllObjects];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)isRunning
|
- (BOOL)isRunning {
|
||||||
{
|
|
||||||
return self.runningOperations.count > 0;
|
return self.runningOperations.count > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,28 +229,22 @@
|
||||||
|
|
||||||
@implementation SDWebImageCombinedOperation
|
@implementation SDWebImageCombinedOperation
|
||||||
|
|
||||||
- (void)setCancelBlock:(void (^)())cancelBlock
|
- (void)setCancelBlock:(void (^)())cancelBlock {
|
||||||
{
|
if (self.isCancelled) {
|
||||||
if (self.isCancelled)
|
|
||||||
{
|
|
||||||
if (cancelBlock) cancelBlock();
|
if (cancelBlock) cancelBlock();
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
_cancelBlock = [cancelBlock copy];
|
_cancelBlock = [cancelBlock copy];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)cancel
|
- (void)cancel {
|
||||||
{
|
|
||||||
self.cancelled = YES;
|
self.cancelled = YES;
|
||||||
if (self.cacheOperation)
|
if (self.cacheOperation) {
|
||||||
{
|
|
||||||
[self.cacheOperation cancel];
|
[self.cacheOperation cancel];
|
||||||
self.cacheOperation = nil;
|
self.cacheOperation = nil;
|
||||||
}
|
}
|
||||||
if (self.cancelBlock)
|
if (self.cancelBlock) {
|
||||||
{
|
|
||||||
self.cancelBlock();
|
self.cancelBlock();
|
||||||
self.cancelBlock = nil;
|
self.cancelBlock = nil;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
* @param finishedCount The total number of images that were prefetched
|
* @param finishedCount The total number of images that were prefetched
|
||||||
* @param totalCount The total number of images that need to be prefetched
|
* @param totalCount The total number of images that need to be prefetched
|
||||||
*/
|
*/
|
||||||
- (void)imagePrefetcher:(SDWebImagePrefetcher*)imagePrefetcher didPrefetchURL:(NSURL*)imageURL finishedCount:(NSUInteger)finishedCount totalCount:(NSUInteger)totalCount;
|
- (void)imagePrefetcher:(SDWebImagePrefetcher *)imagePrefetcher didPrefetchURL:(NSURL *)imageURL finishedCount:(NSUInteger)finishedCount totalCount:(NSUInteger)totalCount;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when all images are prefetched.
|
* Called when all images are prefetched.
|
||||||
|
@ -31,7 +31,7 @@
|
||||||
* @param totalCount The total number of images that need to be prefetched
|
* @param totalCount The total number of images that need to be prefetched
|
||||||
* @param skippedCount The total number of images that were skipped
|
* @param skippedCount The total number of images that were skipped
|
||||||
*/
|
*/
|
||||||
- (void)imagePrefetcher:(SDWebImagePrefetcher*)imagePrefetcher didFinishWithTotalCount:(NSUInteger)totalCount skippedCount:(NSUInteger)skippedCount;
|
- (void)imagePrefetcher:(SDWebImagePrefetcher *)imagePrefetcher didFinishWithTotalCount:(NSUInteger)totalCount skippedCount:(NSUInteger)skippedCount;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@
|
||||||
*/
|
*/
|
||||||
@property (nonatomic, assign) SDWebImageOptions options;
|
@property (nonatomic, assign) SDWebImageOptions options;
|
||||||
|
|
||||||
@property (weak, nonatomic) id<SDWebImagePrefetcherDelegate> delegate;
|
@property (weak, nonatomic) id <SDWebImagePrefetcherDelegate> delegate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the global image prefetcher instance.
|
* Return the global image prefetcher instance.
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#import "SDWebImagePrefetcher.h"
|
#import "SDWebImagePrefetcher.h"
|
||||||
#import "SDWebImageManager.h"
|
|
||||||
|
|
||||||
@interface SDWebImagePrefetcher ()
|
@interface SDWebImagePrefetcher ()
|
||||||
|
|
||||||
|
@ -23,18 +22,17 @@
|
||||||
|
|
||||||
@implementation SDWebImagePrefetcher
|
@implementation SDWebImagePrefetcher
|
||||||
|
|
||||||
+ (SDWebImagePrefetcher *)sharedImagePrefetcher
|
+ (SDWebImagePrefetcher *)sharedImagePrefetcher {
|
||||||
{
|
|
||||||
static dispatch_once_t once;
|
static dispatch_once_t once;
|
||||||
static id instance;
|
static id instance;
|
||||||
dispatch_once(&once, ^{instance = self.new;});
|
dispatch_once(&once, ^{
|
||||||
|
instance = self.new;
|
||||||
|
});
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)init
|
- (id)init {
|
||||||
{
|
if ((self = [super init])) {
|
||||||
if ((self = [super init]))
|
|
||||||
{
|
|
||||||
_manager = SDWebImageManager.new;
|
_manager = SDWebImageManager.new;
|
||||||
_options = SDWebImageLowPriority;
|
_options = SDWebImageLowPriority;
|
||||||
self.maxConcurrentDownloads = 3;
|
self.maxConcurrentDownloads = 3;
|
||||||
|
@ -42,33 +40,27 @@
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setMaxConcurrentDownloads:(NSUInteger)maxConcurrentDownloads
|
- (void)setMaxConcurrentDownloads:(NSUInteger)maxConcurrentDownloads {
|
||||||
{
|
|
||||||
self.manager.imageDownloader.maxConcurrentDownloads = maxConcurrentDownloads;
|
self.manager.imageDownloader.maxConcurrentDownloads = maxConcurrentDownloads;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSUInteger)maxConcurrentDownloads
|
- (NSUInteger)maxConcurrentDownloads {
|
||||||
{
|
|
||||||
return self.manager.imageDownloader.maxConcurrentDownloads;
|
return self.manager.imageDownloader.maxConcurrentDownloads;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)startPrefetchingAtIndex:(NSUInteger)index
|
- (void)startPrefetchingAtIndex:(NSUInteger)index {
|
||||||
{
|
|
||||||
if (index >= self.prefetchURLs.count) return;
|
if (index >= self.prefetchURLs.count) return;
|
||||||
self.requestedCount++;
|
self.requestedCount++;
|
||||||
[self.manager downloadWithURL:self.prefetchURLs[index] options:self.options progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished)
|
[self.manager downloadWithURL:self.prefetchURLs[index] options:self.options progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished) {
|
||||||
{
|
|
||||||
if (!finished) return;
|
if (!finished) return;
|
||||||
self.finishedCount++;
|
self.finishedCount++;
|
||||||
|
|
||||||
if (image)
|
if (image) {
|
||||||
{
|
|
||||||
#ifdef SD_VERBOSE
|
#ifdef SD_VERBOSE
|
||||||
NSLog(@"Prefetched %d out of %d", self.finishedCount, self.prefetchURLs.count);
|
NSLog(@"Prefetched %d out of %d", self.finishedCount, self.prefetchURLs.count);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
#ifdef SD_VERBOSE
|
#ifdef SD_VERBOSE
|
||||||
NSLog(@"Prefetched %d out of %d (Failed)", self.finishedCount, [self.prefetchURLs count]);
|
NSLog(@"Prefetched %d out of %d (Failed)", self.finishedCount, [self.prefetchURLs count]);
|
||||||
#endif
|
#endif
|
||||||
|
@ -76,24 +68,20 @@
|
||||||
// Add last failed
|
// Add last failed
|
||||||
self.skippedCount++;
|
self.skippedCount++;
|
||||||
}
|
}
|
||||||
if ([self.delegate respondsToSelector:@selector(imagePrefetcher:didPrefetchURL:finishedCount:totalCount:)])
|
if ([self.delegate respondsToSelector:@selector(imagePrefetcher:didPrefetchURL:finishedCount:totalCount:)]) {
|
||||||
{
|
|
||||||
[self.delegate imagePrefetcher:self
|
[self.delegate imagePrefetcher:self
|
||||||
didPrefetchURL:self.prefetchURLs[index]
|
didPrefetchURL:self.prefetchURLs[index]
|
||||||
finishedCount:self.finishedCount
|
finishedCount:self.finishedCount
|
||||||
totalCount:self.prefetchURLs.count
|
totalCount:self.prefetchURLs.count
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.prefetchURLs.count > self.requestedCount)
|
if (self.prefetchURLs.count > self.requestedCount) {
|
||||||
{
|
|
||||||
[self startPrefetchingAtIndex:self.requestedCount];
|
[self startPrefetchingAtIndex:self.requestedCount];
|
||||||
}
|
}
|
||||||
else if (self.finishedCount == self.requestedCount)
|
else if (self.finishedCount == self.requestedCount) {
|
||||||
{
|
|
||||||
[self reportStatus];
|
[self reportStatus];
|
||||||
if (self.completionBlock)
|
if (self.completionBlock) {
|
||||||
{
|
|
||||||
self.completionBlock(self.finishedCount, self.skippedCount);
|
self.completionBlock(self.finishedCount, self.skippedCount);
|
||||||
self.completionBlock = nil;
|
self.completionBlock = nil;
|
||||||
}
|
}
|
||||||
|
@ -101,28 +89,24 @@
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)reportStatus
|
- (void)reportStatus {
|
||||||
{
|
|
||||||
NSUInteger total = [self.prefetchURLs count];
|
NSUInteger total = [self.prefetchURLs count];
|
||||||
#ifdef SD_VERBOSE
|
#ifdef SD_VERBOSE
|
||||||
NSLog(@"Finished prefetching (%d successful, %d skipped, timeElasped %.2f)", total - self.skippedCount, self.skippedCount, CFAbsoluteTimeGetCurrent() - self.startedTime);
|
NSLog(@"Finished prefetching (%d successful, %d skipped, timeElasped %.2f)", total - self.skippedCount, self.skippedCount, CFAbsoluteTimeGetCurrent() - self.startedTime);
|
||||||
#endif
|
#endif
|
||||||
if ([self.delegate respondsToSelector:@selector(imagePrefetcher:didFinishWithTotalCount:skippedCount:)])
|
if ([self.delegate respondsToSelector:@selector(imagePrefetcher:didFinishWithTotalCount:skippedCount:)]) {
|
||||||
{
|
|
||||||
[self.delegate imagePrefetcher:self
|
[self.delegate imagePrefetcher:self
|
||||||
didFinishWithTotalCount:(total - self.skippedCount)
|
didFinishWithTotalCount:(total - self.skippedCount)
|
||||||
skippedCount:self.skippedCount
|
skippedCount:self.skippedCount
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)prefetchURLs:(NSArray *)urls
|
- (void)prefetchURLs:(NSArray *)urls {
|
||||||
{
|
|
||||||
[self prefetchURLs:urls completed:nil];
|
[self prefetchURLs:urls completed:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)prefetchURLs:(NSArray *)urls completed:(void (^)(NSUInteger, NSUInteger))completionBlock
|
- (void)prefetchURLs:(NSArray *)urls completed:(void (^)(NSUInteger, NSUInteger))completionBlock {
|
||||||
{
|
|
||||||
[self cancelPrefetching]; // Prevent duplicate prefetch request
|
[self cancelPrefetching]; // Prevent duplicate prefetch request
|
||||||
self.startedTime = CFAbsoluteTimeGetCurrent();
|
self.startedTime = CFAbsoluteTimeGetCurrent();
|
||||||
self.prefetchURLs = urls;
|
self.prefetchURLs = urls;
|
||||||
|
@ -130,14 +114,12 @@
|
||||||
|
|
||||||
// Starts prefetching from the very first image on the list with the max allowed concurrency
|
// Starts prefetching from the very first image on the list with the max allowed concurrency
|
||||||
NSUInteger listCount = self.prefetchURLs.count;
|
NSUInteger listCount = self.prefetchURLs.count;
|
||||||
for (NSUInteger i = 0; i < self.maxConcurrentDownloads && self.requestedCount < listCount; i++)
|
for (NSUInteger i = 0; i < self.maxConcurrentDownloads && self.requestedCount < listCount; i++) {
|
||||||
{
|
|
||||||
[self startPrefetchingAtIndex:i];
|
[self startPrefetchingAtIndex:i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)cancelPrefetching
|
- (void)cancelPrefetching {
|
||||||
{
|
|
||||||
self.prefetchURLs = nil;
|
self.prefetchURLs = nil;
|
||||||
self.skippedCount = 0;
|
self.skippedCount = 0;
|
||||||
self.requestedCount = 0;
|
self.requestedCount = 0;
|
||||||
|
|
|
@ -13,52 +13,42 @@ static char operationKey;
|
||||||
|
|
||||||
@implementation UIButton (WebCache)
|
@implementation UIButton (WebCache)
|
||||||
|
|
||||||
- (void)setImageWithURL:(NSURL *)url forState:(UIControlState)state
|
- (void)setImageWithURL:(NSURL *)url forState:(UIControlState)state {
|
||||||
{
|
|
||||||
[self setImageWithURL:url forState:state placeholderImage:nil options:0 completed:nil];
|
[self setImageWithURL:url forState:state placeholderImage:nil options:0 completed:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder
|
- (void)setImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder {
|
||||||
{
|
|
||||||
[self setImageWithURL:url forState:state placeholderImage:placeholder options:0 completed:nil];
|
[self setImageWithURL:url forState:state placeholderImage:placeholder options:0 completed:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options
|
- (void)setImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options {
|
||||||
{
|
|
||||||
[self setImageWithURL:url forState:state placeholderImage:placeholder options:options completed:nil];
|
[self setImageWithURL:url forState:state placeholderImage:placeholder options:options completed:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setImageWithURL:(NSURL *)url forState:(UIControlState)state completed:(SDWebImageCompletedBlock)completedBlock
|
- (void)setImageWithURL:(NSURL *)url forState:(UIControlState)state completed:(SDWebImageCompletedBlock)completedBlock {
|
||||||
{
|
|
||||||
[self setImageWithURL:url forState:state placeholderImage:nil options:0 completed:completedBlock];
|
[self setImageWithURL:url forState:state placeholderImage:nil options:0 completed:completedBlock];
|
||||||
}
|
}
|
||||||
- (void)setImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder completed:(SDWebImageCompletedBlock)completedBlock
|
|
||||||
{
|
- (void)setImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder completed:(SDWebImageCompletedBlock)completedBlock {
|
||||||
[self setImageWithURL:url forState:state placeholderImage:placeholder options:0 completed:completedBlock];
|
[self setImageWithURL:url forState:state placeholderImage:placeholder options:0 completed:completedBlock];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options completed:(SDWebImageCompletedBlock)completedBlock
|
- (void)setImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options completed:(SDWebImageCompletedBlock)completedBlock {
|
||||||
{
|
|
||||||
[self cancelCurrentImageLoad];
|
[self cancelCurrentImageLoad];
|
||||||
|
|
||||||
[self setImage:placeholder forState:state];
|
[self setImage:placeholder forState:state];
|
||||||
|
|
||||||
if (url)
|
if (url) {
|
||||||
{
|
|
||||||
__weak UIButton *wself = self;
|
__weak UIButton *wself = self;
|
||||||
id<SDWebImageOperation> operation = [SDWebImageManager.sharedManager downloadWithURL:url options:options progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished)
|
id <SDWebImageOperation> operation = [SDWebImageManager.sharedManager downloadWithURL:url options:options progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished) {
|
||||||
{
|
|
||||||
if (!wself) return;
|
if (!wself) return;
|
||||||
dispatch_main_sync_safe(^
|
dispatch_main_sync_safe(^{
|
||||||
{
|
|
||||||
__strong UIButton *sself = wself;
|
__strong UIButton *sself = wself;
|
||||||
if (!sself) return;
|
if (!sself) return;
|
||||||
if (image)
|
if (image) {
|
||||||
{
|
|
||||||
[sself setImage:image forState:state];
|
[sself setImage:image forState:state];
|
||||||
}
|
}
|
||||||
if (completedBlock && finished)
|
if (completedBlock && finished) {
|
||||||
{
|
|
||||||
completedBlock(image, error, cacheType);
|
completedBlock(image, error, cacheType);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -67,53 +57,42 @@ static char operationKey;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setBackgroundImageWithURL:(NSURL *)url forState:(UIControlState)state
|
- (void)setBackgroundImageWithURL:(NSURL *)url forState:(UIControlState)state {
|
||||||
{
|
|
||||||
[self setBackgroundImageWithURL:url forState:state placeholderImage:nil options:0 completed:nil];
|
[self setBackgroundImageWithURL:url forState:state placeholderImage:nil options:0 completed:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setBackgroundImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder
|
- (void)setBackgroundImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder {
|
||||||
{
|
|
||||||
[self setBackgroundImageWithURL:url forState:state placeholderImage:placeholder options:0 completed:nil];
|
[self setBackgroundImageWithURL:url forState:state placeholderImage:placeholder options:0 completed:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setBackgroundImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options
|
- (void)setBackgroundImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options {
|
||||||
{
|
|
||||||
[self setBackgroundImageWithURL:url forState:state placeholderImage:placeholder options:options completed:nil];
|
[self setBackgroundImageWithURL:url forState:state placeholderImage:placeholder options:options completed:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setBackgroundImageWithURL:(NSURL *)url forState:(UIControlState)state completed:(SDWebImageCompletedBlock)completedBlock
|
- (void)setBackgroundImageWithURL:(NSURL *)url forState:(UIControlState)state completed:(SDWebImageCompletedBlock)completedBlock {
|
||||||
{
|
|
||||||
[self setBackgroundImageWithURL:url forState:state placeholderImage:nil options:0 completed:completedBlock];
|
[self setBackgroundImageWithURL:url forState:state placeholderImage:nil options:0 completed:completedBlock];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setBackgroundImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder completed:(SDWebImageCompletedBlock)completedBlock
|
- (void)setBackgroundImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder completed:(SDWebImageCompletedBlock)completedBlock {
|
||||||
{
|
|
||||||
[self setBackgroundImageWithURL:url forState:state placeholderImage:placeholder options:0 completed:completedBlock];
|
[self setBackgroundImageWithURL:url forState:state placeholderImage:placeholder options:0 completed:completedBlock];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setBackgroundImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options completed:(SDWebImageCompletedBlock)completedBlock
|
- (void)setBackgroundImageWithURL:(NSURL *)url forState:(UIControlState)state placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options completed:(SDWebImageCompletedBlock)completedBlock {
|
||||||
{
|
|
||||||
[self cancelCurrentImageLoad];
|
[self cancelCurrentImageLoad];
|
||||||
|
|
||||||
[self setBackgroundImage:placeholder forState:state];
|
[self setBackgroundImage:placeholder forState:state];
|
||||||
|
|
||||||
if (url)
|
if (url) {
|
||||||
{
|
|
||||||
__weak UIButton *wself = self;
|
__weak UIButton *wself = self;
|
||||||
id<SDWebImageOperation> operation = [SDWebImageManager.sharedManager downloadWithURL:url options:options progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished)
|
id <SDWebImageOperation> operation = [SDWebImageManager.sharedManager downloadWithURL:url options:options progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished) {
|
||||||
{
|
|
||||||
if (!wself) return;
|
if (!wself) return;
|
||||||
dispatch_main_sync_safe(^
|
dispatch_main_sync_safe(^{
|
||||||
{
|
|
||||||
__strong UIButton *sself = wself;
|
__strong UIButton *sself = wself;
|
||||||
if (!sself) return;
|
if (!sself) return;
|
||||||
if (image)
|
if (image) {
|
||||||
{
|
|
||||||
[sself setBackgroundImage:image forState:state];
|
[sself setBackgroundImage:image forState:state];
|
||||||
}
|
}
|
||||||
if (completedBlock && finished)
|
if (completedBlock && finished) {
|
||||||
{
|
|
||||||
completedBlock(image, error, cacheType);
|
completedBlock(image, error, cacheType);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -123,12 +102,10 @@ static char operationKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void)cancelCurrentImageLoad
|
- (void)cancelCurrentImageLoad {
|
||||||
{
|
|
||||||
// Cancel in progress downloader from queue
|
// Cancel in progress downloader from queue
|
||||||
id<SDWebImageOperation> operation = objc_getAssociatedObject(self, &operationKey);
|
id <SDWebImageOperation> operation = objc_getAssociatedObject(self, &operationKey);
|
||||||
if (operation)
|
if (operation) {
|
||||||
{
|
|
||||||
[operation cancel];
|
[operation cancel];
|
||||||
objc_setAssociatedObject(self, &operationKey, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
objc_setAssociatedObject(self, &operationKey, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
@interface UIImage (GIF)
|
@interface UIImage (GIF)
|
||||||
|
|
||||||
+ (UIImage *)sd_animatedGIFNamed:(NSString *)name;
|
+ (UIImage *)sd_animatedGIFNamed:(NSString *)name;
|
||||||
|
|
||||||
+ (UIImage *)sd_animatedGIFWithData:(NSData *)data;
|
+ (UIImage *)sd_animatedGIFWithData:(NSData *)data;
|
||||||
|
|
||||||
- (UIImage *)sd_animatedImageByScalingAndCroppingToSize:(CGSize)size;
|
- (UIImage *)sd_animatedImageByScalingAndCroppingToSize:(CGSize)size;
|
||||||
|
|
|
@ -11,10 +11,8 @@
|
||||||
|
|
||||||
@implementation UIImage (GIF)
|
@implementation UIImage (GIF)
|
||||||
|
|
||||||
+ (UIImage *)sd_animatedGIFWithData:(NSData *)data
|
+ (UIImage *)sd_animatedGIFWithData:(NSData *)data {
|
||||||
{
|
if (!data) {
|
||||||
if (!data)
|
|
||||||
{
|
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,18 +22,15 @@
|
||||||
|
|
||||||
UIImage *animatedImage;
|
UIImage *animatedImage;
|
||||||
|
|
||||||
if (count <= 1)
|
if (count <= 1) {
|
||||||
{
|
|
||||||
animatedImage = [[UIImage alloc] initWithData:data];
|
animatedImage = [[UIImage alloc] initWithData:data];
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
NSMutableArray *images = [NSMutableArray array];
|
NSMutableArray *images = [NSMutableArray array];
|
||||||
|
|
||||||
NSTimeInterval duration = 0.0f;
|
NSTimeInterval duration = 0.0f;
|
||||||
|
|
||||||
for (size_t i = 0; i < count; i++)
|
for (size_t i = 0; i < count; i++) {
|
||||||
{
|
|
||||||
CGImageRef image = CGImageSourceCreateImageAtIndex(source, i, NULL);
|
CGImageRef image = CGImageSourceCreateImageAtIndex(source, i, NULL);
|
||||||
|
|
||||||
duration += [self frameDurationAtIndex:i source:source];
|
duration += [self frameDurationAtIndex:i source:source];
|
||||||
|
@ -45,9 +40,8 @@
|
||||||
CGImageRelease(image);
|
CGImageRelease(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!duration)
|
if (!duration) {
|
||||||
{
|
duration = (1.0f / 10.0f) * count;
|
||||||
duration = (1.0f/10.0f)*count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
animatedImage = [UIImage animatedImageWithImages:images duration:duration];
|
animatedImage = [UIImage animatedImageWithImages:images duration:duration];
|
||||||
|
@ -58,24 +52,20 @@
|
||||||
return animatedImage;
|
return animatedImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (float)frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source
|
+ (float)frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source {
|
||||||
{
|
|
||||||
float frameDuration = 0.1f;
|
float frameDuration = 0.1f;
|
||||||
CFDictionaryRef cfFrameProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil);
|
CFDictionaryRef cfFrameProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil);
|
||||||
NSDictionary *frameProperties = (__bridge NSDictionary *)cfFrameProperties;
|
NSDictionary *frameProperties = (__bridge NSDictionary *)cfFrameProperties;
|
||||||
NSDictionary *gifProperties = frameProperties[(NSString *)kCGImagePropertyGIFDictionary];
|
NSDictionary *gifProperties = frameProperties[(NSString *)kCGImagePropertyGIFDictionary];
|
||||||
|
|
||||||
NSNumber *delayTimeUnclampedProp = gifProperties[(NSString *)kCGImagePropertyGIFUnclampedDelayTime];
|
NSNumber *delayTimeUnclampedProp = gifProperties[(NSString *)kCGImagePropertyGIFUnclampedDelayTime];
|
||||||
if (delayTimeUnclampedProp)
|
if (delayTimeUnclampedProp) {
|
||||||
{
|
|
||||||
frameDuration = [delayTimeUnclampedProp floatValue];
|
frameDuration = [delayTimeUnclampedProp floatValue];
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
|
|
||||||
NSNumber *delayTimeProp = gifProperties[(NSString *)kCGImagePropertyGIFDelayTime];
|
NSNumber *delayTimeProp = gifProperties[(NSString *)kCGImagePropertyGIFDelayTime];
|
||||||
if (delayTimeProp)
|
if (delayTimeProp) {
|
||||||
{
|
|
||||||
frameDuration = [delayTimeProp floatValue];
|
frameDuration = [delayTimeProp floatValue];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,8 +75,7 @@
|
||||||
// a duration of <= 10 ms. See <rdar://problem/7689300> and <http://webkit.org/b/36082>
|
// a duration of <= 10 ms. See <rdar://problem/7689300> and <http://webkit.org/b/36082>
|
||||||
// for more information.
|
// for more information.
|
||||||
|
|
||||||
if (frameDuration < 0.011f)
|
if (frameDuration < 0.011f) {
|
||||||
{
|
|
||||||
frameDuration = 0.100f;
|
frameDuration = 0.100f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,18 +83,15 @@
|
||||||
return frameDuration;
|
return frameDuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (UIImage *)sd_animatedGIFNamed:(NSString *)name
|
+ (UIImage *)sd_animatedGIFNamed:(NSString *)name {
|
||||||
{
|
|
||||||
CGFloat scale = [UIScreen mainScreen].scale;
|
CGFloat scale = [UIScreen mainScreen].scale;
|
||||||
|
|
||||||
if (scale > 1.0f)
|
if (scale > 1.0f) {
|
||||||
{
|
|
||||||
NSString *retinaPath = [[NSBundle mainBundle] pathForResource:[name stringByAppendingString:@"@2x"] ofType:@"gif"];
|
NSString *retinaPath = [[NSBundle mainBundle] pathForResource:[name stringByAppendingString:@"@2x"] ofType:@"gif"];
|
||||||
|
|
||||||
NSData *data = [NSData dataWithContentsOfFile:retinaPath];
|
NSData *data = [NSData dataWithContentsOfFile:retinaPath];
|
||||||
|
|
||||||
if (data)
|
if (data) {
|
||||||
{
|
|
||||||
return [UIImage sd_animatedGIFWithData:data];
|
return [UIImage sd_animatedGIFWithData:data];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,21 +99,18 @@
|
||||||
|
|
||||||
data = [NSData dataWithContentsOfFile:path];
|
data = [NSData dataWithContentsOfFile:path];
|
||||||
|
|
||||||
if (data)
|
if (data) {
|
||||||
{
|
|
||||||
return [UIImage sd_animatedGIFWithData:data];
|
return [UIImage sd_animatedGIFWithData:data];
|
||||||
}
|
}
|
||||||
|
|
||||||
return [UIImage imageNamed:name];
|
return [UIImage imageNamed:name];
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:@"gif"];
|
NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:@"gif"];
|
||||||
|
|
||||||
NSData *data = [NSData dataWithContentsOfFile:path];
|
NSData *data = [NSData dataWithContentsOfFile:path];
|
||||||
|
|
||||||
if (data)
|
if (data) {
|
||||||
{
|
|
||||||
return [UIImage sd_animatedGIFWithData:data];
|
return [UIImage sd_animatedGIFWithData:data];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,10 +118,8 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (UIImage *)sd_animatedImageByScalingAndCroppingToSize:(CGSize)size
|
- (UIImage *)sd_animatedImageByScalingAndCroppingToSize:(CGSize)size {
|
||||||
{
|
if (CGSizeEqualToSize(self.size, size) || CGSizeEqualToSize(size, CGSizeZero)) {
|
||||||
if (CGSizeEqualToSize(self.size, size) || CGSizeEqualToSize(size, CGSizeZero))
|
|
||||||
{
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,16 +128,14 @@
|
||||||
|
|
||||||
CGFloat widthFactor = size.width / self.size.width;
|
CGFloat widthFactor = size.width / self.size.width;
|
||||||
CGFloat heightFactor = size.height / self.size.height;
|
CGFloat heightFactor = size.height / self.size.height;
|
||||||
CGFloat scaleFactor = (widthFactor > heightFactor) ? widthFactor :heightFactor;
|
CGFloat scaleFactor = (widthFactor > heightFactor) ? widthFactor : heightFactor;
|
||||||
scaledSize.width = self.size.width * scaleFactor;
|
scaledSize.width = self.size.width * scaleFactor;
|
||||||
scaledSize.height = self.size.height * scaleFactor;
|
scaledSize.height = self.size.height * scaleFactor;
|
||||||
|
|
||||||
if (widthFactor > heightFactor)
|
if (widthFactor > heightFactor) {
|
||||||
{
|
|
||||||
thumbnailPoint.y = (size.height - scaledSize.height) * 0.5;
|
thumbnailPoint.y = (size.height - scaledSize.height) * 0.5;
|
||||||
}
|
}
|
||||||
else if (widthFactor < heightFactor)
|
else if (widthFactor < heightFactor) {
|
||||||
{
|
|
||||||
thumbnailPoint.x = (size.width - scaledSize.width) * 0.5;
|
thumbnailPoint.x = (size.width - scaledSize.width) * 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,8 +143,7 @@
|
||||||
|
|
||||||
UIGraphicsBeginImageContextWithOptions(size, NO, 0.0);
|
UIGraphicsBeginImageContextWithOptions(size, NO, 0.0);
|
||||||
|
|
||||||
for (UIImage *image in self.images)
|
for (UIImage *image in self.images) {
|
||||||
{
|
|
||||||
[image drawInRect:CGRectMake(thumbnailPoint.x, thumbnailPoint.y, scaledSize.width, scaledSize.height)];
|
[image drawInRect:CGRectMake(thumbnailPoint.x, thumbnailPoint.y, scaledSize.width, scaledSize.height)];
|
||||||
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
|
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||||
|
|
||||||
|
|
|
@ -9,18 +9,17 @@
|
||||||
#import "UIImage+MultiFormat.h"
|
#import "UIImage+MultiFormat.h"
|
||||||
#import "UIImage+GIF.h"
|
#import "UIImage+GIF.h"
|
||||||
#import "NSData+ImageContentType.h"
|
#import "NSData+ImageContentType.h"
|
||||||
|
|
||||||
#ifdef SD_WEBP
|
#ifdef SD_WEBP
|
||||||
#import "UIImage+WebP.h"
|
#import "UIImage+WebP.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@implementation UIImage (MultiFormat)
|
@implementation UIImage (MultiFormat)
|
||||||
|
|
||||||
+ (UIImage *)sd_imageWithData:(NSData *)data
|
+ (UIImage *)sd_imageWithData:(NSData *)data {
|
||||||
{
|
|
||||||
UIImage *image;
|
UIImage *image;
|
||||||
NSString *imageContentType = [NSData contentTypeForImageData:data];
|
NSString *imageContentType = [NSData contentTypeForImageData:data];
|
||||||
if ([imageContentType isEqualToString:@"image/gif"])
|
if ([imageContentType isEqualToString:@"image/gif"]) {
|
||||||
{
|
|
||||||
image = [UIImage sd_animatedGIFWithData:data];
|
image = [UIImage sd_animatedGIFWithData:data];
|
||||||
}
|
}
|
||||||
#ifdef SD_WEBP
|
#ifdef SD_WEBP
|
||||||
|
@ -29,13 +28,11 @@
|
||||||
image = [UIImage sd_imageWithWebPData:data];
|
image = [UIImage sd_imageWithWebPData:data];
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
image = [[UIImage alloc] initWithData:data];
|
image = [[UIImage alloc] initWithData:data];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,11 +7,14 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifdef SD_WEBP
|
#ifdef SD_WEBP
|
||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
// Fix for issue #416 Undefined symbols for architecture armv7 since WebP introduction when deploying to device
|
// Fix for issue #416 Undefined symbols for architecture armv7 since WebP introduction when deploying to device
|
||||||
void WebPInitPremultiplyNEON(void);
|
void WebPInitPremultiplyNEON(void);
|
||||||
|
|
||||||
void WebPInitUpsamplersNEON(void);
|
void WebPInitUpsamplersNEON(void);
|
||||||
|
|
||||||
void VP8DspInitNEON(void);
|
void VP8DspInitNEON(void);
|
||||||
|
|
||||||
@interface UIImage (WebP)
|
@interface UIImage (WebP)
|
||||||
|
@ -19,4 +22,5 @@ void VP8DspInitNEON(void);
|
||||||
+ (UIImage *)sd_imageWithWebPData:(NSData *)data;
|
+ (UIImage *)sd_imageWithWebPData:(NSData *)data;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -139,7 +139,7 @@
|
||||||
*
|
*
|
||||||
*@param arrayOfURLs An array of NSURL
|
*@param arrayOfURLs An array of NSURL
|
||||||
*/
|
*/
|
||||||
-(void)setAnimationImagesWithURLs:(NSArray *)arrayOfURLs;
|
- (void)setAnimationImagesWithURLs:(NSArray *)arrayOfURLs;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cancel the current download
|
* Cancel the current download
|
||||||
|
|
|
@ -14,58 +14,46 @@ static char operationArrayKey;
|
||||||
|
|
||||||
@implementation UIImageView (WebCache)
|
@implementation UIImageView (WebCache)
|
||||||
|
|
||||||
- (void)setImageWithURL:(NSURL *)url
|
- (void)setImageWithURL:(NSURL *)url {
|
||||||
{
|
|
||||||
[self setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:nil];
|
[self setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder
|
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder {
|
||||||
{
|
|
||||||
[self setImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:nil];
|
[self setImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options
|
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options {
|
||||||
{
|
|
||||||
[self setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:nil];
|
[self setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setImageWithURL:(NSURL *)url completed:(SDWebImageCompletedBlock)completedBlock
|
- (void)setImageWithURL:(NSURL *)url completed:(SDWebImageCompletedBlock)completedBlock {
|
||||||
{
|
|
||||||
[self setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:completedBlock];
|
[self setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:completedBlock];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder completed:(SDWebImageCompletedBlock)completedBlock
|
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder completed:(SDWebImageCompletedBlock)completedBlock {
|
||||||
{
|
|
||||||
[self setImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:completedBlock];
|
[self setImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:completedBlock];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options completed:(SDWebImageCompletedBlock)completedBlock
|
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options completed:(SDWebImageCompletedBlock)completedBlock {
|
||||||
{
|
|
||||||
[self setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:completedBlock];
|
[self setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:completedBlock];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletedBlock)completedBlock
|
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletedBlock)completedBlock {
|
||||||
{
|
|
||||||
[self cancelCurrentImageLoad];
|
[self cancelCurrentImageLoad];
|
||||||
|
|
||||||
self.image = placeholder;
|
self.image = placeholder;
|
||||||
|
|
||||||
if (url)
|
if (url) {
|
||||||
{
|
|
||||||
__weak UIImageView *wself = self;
|
__weak UIImageView *wself = self;
|
||||||
id<SDWebImageOperation> operation = [SDWebImageManager.sharedManager downloadWithURL:url options:options progress:progressBlock completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished)
|
id <SDWebImageOperation> operation = [SDWebImageManager.sharedManager downloadWithURL:url options:options progress:progressBlock completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished) {
|
||||||
{
|
|
||||||
if (!wself) return;
|
if (!wself) return;
|
||||||
dispatch_main_sync_safe(^
|
dispatch_main_sync_safe(^{
|
||||||
{
|
|
||||||
if (!wself) return;
|
if (!wself) return;
|
||||||
if (image)
|
if (image) {
|
||||||
{
|
|
||||||
wself.image = image;
|
wself.image = image;
|
||||||
[wself setNeedsLayout];
|
[wself setNeedsLayout];
|
||||||
}
|
}
|
||||||
if (completedBlock && finished)
|
if (completedBlock && finished) {
|
||||||
{
|
|
||||||
completedBlock(image, error, cacheType);
|
completedBlock(image, error, cacheType);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -74,27 +62,21 @@ static char operationArrayKey;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setAnimationImagesWithURLs:(NSArray *)arrayOfURLs
|
- (void)setAnimationImagesWithURLs:(NSArray *)arrayOfURLs {
|
||||||
{
|
|
||||||
[self cancelCurrentArrayLoad];
|
[self cancelCurrentArrayLoad];
|
||||||
__weak UIImageView *wself = self;
|
__weak UIImageView *wself = self;
|
||||||
|
|
||||||
NSMutableArray *operationsArray = [[NSMutableArray alloc] init];
|
NSMutableArray *operationsArray = [[NSMutableArray alloc] init];
|
||||||
|
|
||||||
for (NSURL *logoImageURL in arrayOfURLs)
|
for (NSURL *logoImageURL in arrayOfURLs) {
|
||||||
{
|
id <SDWebImageOperation> operation = [SDWebImageManager.sharedManager downloadWithURL:logoImageURL options:0 progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished) {
|
||||||
id<SDWebImageOperation> operation = [SDWebImageManager.sharedManager downloadWithURL:logoImageURL options:0 progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished)
|
|
||||||
{
|
|
||||||
if (!wself) return;
|
if (!wself) return;
|
||||||
dispatch_main_sync_safe(^
|
dispatch_main_sync_safe(^{
|
||||||
{
|
|
||||||
__strong UIImageView *sself = wself;
|
__strong UIImageView *sself = wself;
|
||||||
[sself stopAnimating];
|
[sself stopAnimating];
|
||||||
if (sself && image)
|
if (sself && image) {
|
||||||
{
|
|
||||||
NSMutableArray *currentImages = [[sself animationImages] mutableCopy];
|
NSMutableArray *currentImages = [[sself animationImages] mutableCopy];
|
||||||
if (!currentImages)
|
if (!currentImages) {
|
||||||
{
|
|
||||||
currentImages = [[NSMutableArray alloc] init];
|
currentImages = [[NSMutableArray alloc] init];
|
||||||
}
|
}
|
||||||
[currentImages addObject:image];
|
[currentImages addObject:image];
|
||||||
|
@ -111,25 +93,20 @@ static char operationArrayKey;
|
||||||
objc_setAssociatedObject(self, &operationArrayKey, [NSArray arrayWithArray:operationsArray], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
objc_setAssociatedObject(self, &operationArrayKey, [NSArray arrayWithArray:operationsArray], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)cancelCurrentImageLoad
|
- (void)cancelCurrentImageLoad {
|
||||||
{
|
|
||||||
// Cancel in progress downloader from queue
|
// Cancel in progress downloader from queue
|
||||||
id<SDWebImageOperation> operation = objc_getAssociatedObject(self, &operationKey);
|
id <SDWebImageOperation> operation = objc_getAssociatedObject(self, &operationKey);
|
||||||
if (operation)
|
if (operation) {
|
||||||
{
|
|
||||||
[operation cancel];
|
[operation cancel];
|
||||||
objc_setAssociatedObject(self, &operationKey, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
objc_setAssociatedObject(self, &operationKey, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)cancelCurrentArrayLoad
|
- (void)cancelCurrentArrayLoad {
|
||||||
{
|
|
||||||
// Cancel in progress downloader from queue
|
// Cancel in progress downloader from queue
|
||||||
NSArray *operations = objc_getAssociatedObject(self, &operationArrayKey);
|
NSArray *operations = objc_getAssociatedObject(self, &operationArrayKey);
|
||||||
for (id<SDWebImageOperation> operation in operations)
|
for (id <SDWebImageOperation> operation in operations) {
|
||||||
{
|
if (operation) {
|
||||||
if (operation)
|
|
||||||
{
|
|
||||||
[operation cancel];
|
[operation cancel];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue