Merge pull request #1217 from mythodeia/master
Import fixes from @mythodeia 's fork
This commit is contained in:
commit
be560a4090
|
@ -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]]
|
||||||
|
|
|
@ -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.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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];
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue