Merge pull request #1217 from mythodeia/master

Import fixes from @mythodeia 's fork
This commit is contained in:
Bogdan Poplauschi 2015-07-15 23:42:00 +03:00
commit be560a4090
7 changed files with 153 additions and 54 deletions

View File

@ -379,6 +379,9 @@
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
} }
[cell.imageView setShowActivityIndicatorView:YES];
[cell.imageView setIndicatorStyle:UIActivityIndicatorViewStyleGray];
cell.textLabel.text = [NSString stringWithFormat:@"Image #%ld", (long)indexPath.row]; cell.textLabel.text = [NSString stringWithFormat:@"Image #%ld", (long)indexPath.row];
cell.imageView.contentMode = UIViewContentModeScaleAspectFill; cell.imageView.contentMode = UIViewContentModeScaleAspectFill;
[cell.imageView sd_setImageWithURL:[NSURL URLWithString:[_objects objectAtIndex:indexPath.row]] [cell.imageView sd_setImageWithURL:[NSURL URLWithString:[_objects objectAtIndex:indexPath.row]]

View File

@ -42,6 +42,16 @@ typedef void(^SDWebImageCalculateSizeBlock)(NSUInteger fileCount, NSUInteger tot
*/ */
@property (assign, nonatomic) BOOL shouldDecompressImages; @property (assign, nonatomic) BOOL shouldDecompressImages;
/**
* disable iCloud backup [defaults to YES]
*/
@property (assign, nonatomic) BOOL shouldDisableiCloud;
/**
* use memory cache [defaults to YES]
*/
@property (assign, nonatomic) BOOL shouldCacheImagesInMemory;
/** /**
* The maximum "total cost" of the in-memory image cache. The cost function is the number of pixels held in memory. * The maximum "total cost" of the in-memory image cache. The cost function is the number of pixels held in memory.
*/ */

View File

@ -116,6 +116,12 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
// Set decompression to YES // Set decompression to YES
_shouldDecompressImages = YES; _shouldDecompressImages = YES;
// memory cache enabled
_shouldCacheImagesInMemory = YES;
// Disable iCloud
_shouldDisableiCloud = YES;
dispatch_sync(_ioQueue, ^{ dispatch_sync(_ioQueue, ^{
_fileManager = [NSFileManager new]; _fileManager = [NSFileManager new];
}); });
@ -193,9 +199,11 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
if (!image || !key) { if (!image || !key) {
return; return;
} }
// if memory cache is enabled
NSUInteger cost = SDCacheCostForImage(image); if (self.shouldCacheImagesInMemory) {
[self.memCache setObject:image forKey:key cost:cost]; NSUInteger cost = SDCacheCostForImage(image);
[self.memCache setObject:image forKey:key cost:cost];
}
if (toDisk) { if (toDisk) {
dispatch_async(self.ioQueue, ^{ dispatch_async(self.ioQueue, ^{
@ -237,7 +245,17 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
[_fileManager createDirectoryAtPath:_diskCachePath withIntermediateDirectories:YES attributes:nil error:NULL]; [_fileManager createDirectoryAtPath:_diskCachePath withIntermediateDirectories:YES attributes:nil error:NULL];
} }
[_fileManager createFileAtPath:[self defaultCachePathForKey:key] contents:data attributes:nil]; // get cache Path for image key
NSString *cachePathForKey = [self defaultCachePathForKey:key];
// transform to NSUrl
NSURL *fileURL = [NSURL fileURLWithPath:cachePathForKey];
[_fileManager createFileAtPath:cachePathForKey contents:data attributes:nil];
// disable iCloud backup
if (self.shouldDisableiCloud) {
[fileURL setResourceValue:[NSNumber numberWithBool:YES] forKey:NSURLIsExcludedFromBackupKey error:nil];
}
} }
}); });
} }
@ -277,6 +295,7 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
} }
- (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) {
@ -285,7 +304,7 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *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 && self.shouldCacheImagesInMemory) {
NSUInteger cost = SDCacheCostForImage(diskImage); NSUInteger cost = SDCacheCostForImage(diskImage);
[self.memCache setObject:diskImage forKey:key cost:cost]; [self.memCache setObject:diskImage forKey:key cost:cost];
} }
@ -356,7 +375,7 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
@autoreleasepool { @autoreleasepool {
UIImage *diskImage = [self diskImageForKey:key]; UIImage *diskImage = [self diskImageForKey:key];
if (diskImage) { if (diskImage && self.shouldCacheImagesInMemory) {
NSUInteger cost = SDCacheCostForImage(diskImage); NSUInteger cost = SDCacheCostForImage(diskImage);
[self.memCache setObject:diskImage forKey:key cost:cost]; [self.memCache setObject:diskImage forKey:key cost:cost];
} }
@ -387,9 +406,11 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
if (key == nil) { if (key == nil) {
return; return;
} }
[self.memCache removeObjectForKey:key]; if (self.shouldCacheImagesInMemory) {
[self.memCache removeObjectForKey:key];
}
if (fromDisk) { if (fromDisk) {
dispatch_async(self.ioQueue, ^{ dispatch_async(self.ioQueue, ^{
[_fileManager removeItemAtPath:[self defaultCachePathForKey:key] error:nil]; [_fileManager removeItemAtPath:[self defaultCachePathForKey:key] error:nil];

View File

@ -28,7 +28,7 @@ inline UIImage *SDScaledImageForKey(NSString *key, UIImage *image) {
} }
else { else {
if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) { if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) {
CGFloat scale = 1.0; CGFloat scale = [UIScreen mainScreen].scale;
if (key.length >= 8) { if (key.length >= 8) {
NSRange range = [key rangeOfString:@"@2x."]; NSRange range = [key rangeOfString:@"@2x."];
if (range.location != NSNotFound) { if (range.location != NSNotFound) {

View File

@ -13,60 +13,38 @@
@implementation UIImage (ForceDecode) @implementation UIImage (ForceDecode)
+ (UIImage *)decodedImageWithImage:(UIImage *)image { + (UIImage *)decodedImageWithImage:(UIImage *)image {
if (image.images) { // do not decode animated images
// Do not decode animated images if (image.images) { return image; }
return image;
}
CGImageRef imageRef = image.CGImage; CGImageRef imageRef = image.CGImage;
CGSize imageSize = CGSizeMake(CGImageGetWidth(imageRef), CGImageGetHeight(imageRef));
CGRect imageRect = (CGRect){.origin = CGPointZero, .size = imageSize};
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); CGImageAlphaInfo alpha = CGImageGetAlphaInfo(imageRef);
CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef); BOOL anyAlpha = (alpha == kCGImageAlphaFirst ||
alpha == kCGImageAlphaLast ||
alpha == kCGImageAlphaPremultipliedFirst ||
alpha == kCGImageAlphaPremultipliedLast);
int infoMask = (bitmapInfo & kCGBitmapAlphaInfoMask); if (anyAlpha) { return image; }
BOOL anyNonAlpha = (infoMask == kCGImageAlphaNone ||
infoMask == kCGImageAlphaNoneSkipFirst ||
infoMask == kCGImageAlphaNoneSkipLast);
// CGBitmapContextCreate doesn't support kCGImageAlphaNone with RGB. size_t width = CGImageGetWidth(imageRef);
// https://developer.apple.com/library/mac/#qa/qa1037/_index.html size_t height = CGImageGetHeight(imageRef);
if (infoMask == kCGImageAlphaNone && CGColorSpaceGetNumberOfComponents(colorSpace) > 1) {
// Unset the old alpha info.
bitmapInfo &= ~kCGBitmapAlphaInfoMask;
// Set noneSkipFirst. CGContextRef context = CGBitmapContextCreate(NULL, width,
bitmapInfo |= kCGImageAlphaNoneSkipFirst; height,
} CGImageGetBitsPerComponent(imageRef),
// Some PNGs tell us they have alpha but only 3 components. Odd. 0,
else if (!anyNonAlpha && CGColorSpaceGetNumberOfComponents(colorSpace) == 3) { CGImageGetColorSpace(imageRef),
// Unset the old alpha info. kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst);
bitmapInfo &= ~kCGBitmapAlphaInfoMask;
bitmapInfo |= kCGImageAlphaPremultipliedFirst;
}
// It calculates the bytes-per-row based on the bitsPerComponent and width arguments. // Draw the image into the context and retrieve the new image, which will now have an alpha layer
CGContextRef context = CGBitmapContextCreate(NULL, CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
imageSize.width, CGImageRef imageRefWithAlpha = CGBitmapContextCreateImage(context);
imageSize.height, UIImage *imageWithAlpha = [UIImage imageWithCGImage:imageRefWithAlpha];
CGImageGetBitsPerComponent(imageRef),
0,
colorSpace,
bitmapInfo);
CGColorSpaceRelease(colorSpace);
// If failed, return undecompressed image
if (!context) return image;
CGContextDrawImage(context, imageRect, imageRef);
CGImageRef decompressedImageRef = CGBitmapContextCreateImage(context);
CGContextRelease(context); CGContextRelease(context);
CGImageRelease(imageRefWithAlpha);
UIImage *decompressedImage = [UIImage imageWithCGImage:decompressedImageRef scale:image.scale orientation:image.imageOrientation]; return imageWithAlpha;
CGImageRelease(decompressedImageRef);
return decompressedImage;
} }
@end @end

View File

@ -176,6 +176,18 @@
- (void)sd_cancelCurrentAnimationImagesLoad; - (void)sd_cancelCurrentAnimationImagesLoad;
/**
* Show activity UIActivityIndicatorView
*/
- (void)setShowActivityIndicatorView:(BOOL)show;
/**
* set desired UIActivityIndicatorViewStyle
*
* @param style The style of the UIActivityIndicatorView
*/
- (void)setIndicatorStyle:(UIActivityIndicatorViewStyle)style;
@end @end

View File

@ -11,6 +11,9 @@
#import "UIView+WebCacheOperation.h" #import "UIView+WebCacheOperation.h"
static char imageURLKey; static char imageURLKey;
static char TAG_ACTIVITY_INDICATOR;
static char TAG_ACTIVITY_STYLE;
static char TAG_ACTIVITY_SHOW;
@implementation UIImageView (WebCache) @implementation UIImageView (WebCache)
@ -49,8 +52,15 @@ static char imageURLKey;
} }
if (url) { if (url) {
// check if activityView is enabled or not
if ([self showActivityIndicatorView]) {
[self addActivityIndicator];
}
__weak __typeof(self)wself = self; __weak __typeof(self)wself = self;
id <SDWebImageOperation> operation = [SDWebImageManager.sharedManager downloadImageWithURL:url options:options progress:progressBlock completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { id <SDWebImageOperation> operation = [SDWebImageManager.sharedManager downloadImageWithURL:url options:options progress:progressBlock completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
[wself removeActivityIndicator];
if (!wself) return; if (!wself) return;
dispatch_main_sync_safe(^{ dispatch_main_sync_safe(^{
if (!wself) return; if (!wself) return;
@ -76,6 +86,7 @@ static char imageURLKey;
[self sd_setImageLoadOperation:operation forKey:@"UIImageViewImageLoad"]; [self sd_setImageLoadOperation:operation forKey:@"UIImageViewImageLoad"];
} else { } else {
dispatch_main_async_safe(^{ dispatch_main_async_safe(^{
[self removeActivityIndicator];
NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Trying to load a nil url"}]; NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Trying to load a nil url"}];
if (completedBlock) { if (completedBlock) {
completedBlock(nil, error, SDImageCacheTypeNone, url); completedBlock(nil, error, SDImageCacheTypeNone, url);
@ -134,6 +145,70 @@ static char imageURLKey;
[self sd_cancelImageLoadOperationWithKey:@"UIImageViewAnimationImages"]; [self sd_cancelImageLoadOperationWithKey:@"UIImageViewAnimationImages"];
} }
#pragma mark -
- (UIActivityIndicatorView *)activityIndicator {
return (UIActivityIndicatorView *)objc_getAssociatedObject(self, &TAG_ACTIVITY_INDICATOR);
}
- (void)setActivityIndicator:(UIActivityIndicatorView *)activityIndicator {
objc_setAssociatedObject(self, &TAG_ACTIVITY_INDICATOR, activityIndicator, OBJC_ASSOCIATION_RETAIN);
}
- (void)setShowActivityIndicatorView:(BOOL)show{
objc_setAssociatedObject(self, &TAG_ACTIVITY_SHOW, [NSNumber numberWithBool:show], OBJC_ASSOCIATION_RETAIN);
}
- (BOOL)showActivityIndicatorView{
return [objc_getAssociatedObject(self, &TAG_ACTIVITY_SHOW) boolValue];
}
- (void)setIndicatorStyle:(UIActivityIndicatorViewStyle)style{
objc_setAssociatedObject(self, &TAG_ACTIVITY_STYLE, [NSNumber numberWithInt:style], OBJC_ASSOCIATION_RETAIN);
}
- (int)getIndicatorStyle{
return [objc_getAssociatedObject(self, &TAG_ACTIVITY_STYLE) intValue];
}
- (void)addActivityIndicator {
if (!self.activityIndicator) {
self.activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:[self getIndicatorStyle]];
self.activityIndicator.translatesAutoresizingMaskIntoConstraints = NO;
dispatch_main_async_safe(^{
[self addSubview:self.activityIndicator];
[self addConstraint:[NSLayoutConstraint constraintWithItem:self.activityIndicator
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:self.activityIndicator
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeCenterY
multiplier:1.0
constant:0.0]];
});
}
dispatch_main_async_safe(^{
[self.activityIndicator startAnimating];
});
}
- (void)removeActivityIndicator {
if (self.activityIndicator) {
[self.activityIndicator removeFromSuperview];
self.activityIndicator = nil;
}
}
@end @end