Skip to content

Commit

Permalink
Merge upstream for issue:SDWebImage#399 and pull:SDWebImage#444
Browse files Browse the repository at this point in the history
  • Loading branch information
Summer committed Aug 14, 2013
2 parents c35dd03 + 67a28d9 commit ce3f46e
Show file tree
Hide file tree
Showing 12 changed files with 186 additions and 70 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ It's also possible to use the async image downloader independently:
{
// progression tracking code
}
completed:^(UIImage *image, NSError *error, BOOL finished)
completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished)
{
if (image && finished)
{
Expand Down Expand Up @@ -217,7 +217,7 @@ There are two ways to use this in your project: copy all the files into your pro
### Add the SDWebImage project to your project
- Download and unzip the last version of the framework from the [download page](https://github.com/rs/SDWebImage/wiki/Download-Compiled-Framework)
- Download and unzip the last version of the framework from the [download page](https://github.com/rs/SDWebImage/releases)
- Right-click on the project navigator and select "Add Files to "Your Project":
- In the dialog, select SDWebImage.framework:
- Check the "Copy items into destination group's folder (if needed)" checkbox
Expand Down
4 changes: 2 additions & 2 deletions SDWebImage.podspec
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
Pod::Spec.new do |s|
s.name = 'SDWebImage'
s.version = '3.3'
s.version = '3.4'
s.platform = :ios, '5.0'
s.license = 'MIT'
s.summary = 'Asynchronous image downloader with cache support with an UIImageView category.'
s.homepage = 'https://github.com/rs/SDWebImage'
s.author = { 'Olivier Poitrey' => '[email protected]' }
# this source is forked for WanPai
s.source = { :git => 'https://github.com/RoCry/SDWebImage.git', :tag => '3.3' }
s.source = { :git => 'https://github.com/RoCry/SDWebImage.git', :tag => '3.4' }

s.description = 'This library provides a category for UIImageView with support for remote ' \
'images coming from the web. It provides an UIImageView category adding web ' \
Expand Down
12 changes: 2 additions & 10 deletions SDWebImage/MKAnnotationView+WebCache.m
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ - (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder opt
id<SDWebImageOperation> operation = [SDWebImageManager.sharedManager downloadWithURL:url options:options progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished)
{
if (!wself) return;
void (^block)(void) = ^
dispatch_main_sync_safe(^
{
__strong MKAnnotationView *sself = wself;
if (!sself) return;
Expand All @@ -62,15 +62,7 @@ - (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder opt
{
completedBlock(image, error, cacheType);
}
};
if ([NSThread isMainThread])
{
block();
}
else
{
dispatch_sync(dispatch_get_main_queue(), block);
}
});
}];
objc_setAssociatedObject(self, &operationKey, operation, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
Expand Down
2 changes: 1 addition & 1 deletion SDWebImage/SDImageCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ typedef enum SDImageCacheType SDImageCacheType;
*
* @param key The unique key used to store the wanted image
*/
- (void)queryDiskCacheForKey:(NSString *)key done:(void (^)(UIImage *image, SDImageCacheType cacheType))doneBlock;
- (NSOperation *)queryDiskCacheForKey:(NSString *)key done:(void (^)(UIImage *image, SDImageCacheType cacheType))doneBlock;

/**
* Query the memory cache synchronously.
Expand Down
54 changes: 47 additions & 7 deletions SDWebImage/SDImageCache.m
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ - (id)initWithNamespace:(NSString *)ns
selector:@selector(cleanDisk)
name:UIApplicationWillTerminateNotification
object:nil];

[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(backgroundCleanDisk)
name:UIApplicationDidEnterBackgroundNotification
object:nil];
#endif
}

Expand Down Expand Up @@ -112,6 +117,10 @@ - (NSString *)defaultCachePathForKey:(NSString *)key
- (NSString *)cachedFileNameForKey:(NSString *)key
{
const char *str = [key UTF8String];
if (str == NULL)
{
str = "";
}
unsigned char r[CC_MD5_DIGEST_LENGTH];
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",
Expand Down Expand Up @@ -242,26 +251,33 @@ - (UIImage *)scaledImageForKey:(NSString *)key image:(UIImage *)image
return SDScaledImageForKey(key, image);
}

- (void)queryDiskCacheForKey:(NSString *)key done:(void (^)(UIImage *image, SDImageCacheType cacheType))doneBlock
- (NSOperation *)queryDiskCacheForKey:(NSString *)key done:(void (^)(UIImage *image, SDImageCacheType cacheType))doneBlock
{
if (!doneBlock) return;
NSOperation *operation = NSOperation.new;

if (!doneBlock) return nil;

if (!key)
{
doneBlock(nil, SDImageCacheTypeNone);
return;
return nil;
}

// First check the in-memory cache...
UIImage *image = [self imageFromMemoryCacheForKey:key];
if (image)
{
doneBlock(image, SDImageCacheTypeMemory);
return;
return nil;
}

dispatch_async(self.ioQueue, ^
{
if (operation.isCancelled)
{
return;
}

@autoreleasepool
{
UIImage *diskImage = [self diskImageForKey:key];
Expand All @@ -271,12 +287,14 @@ - (void)queryDiskCacheForKey:(NSString *)key done:(void (^)(UIImage *image, SDIm
[self.memCache setObject:diskImage forKey:key cost:cost];
}

dispatch_async(dispatch_get_main_queue(), ^
dispatch_main_sync_safe(^
{
doneBlock(diskImage, SDImageCacheTypeDisk);
});
}
});

return operation;
}

- (void)removeImageForKey:(NSString *)key
Expand Down Expand Up @@ -398,7 +416,29 @@ - (void)cleanDisk
});
}

-(unsigned long long)getSize
- (void)backgroundCleanDisk
{
UIApplication *application = [UIApplication sharedApplication];
__block UIBackgroundTaskIdentifier bgTask = [application beginBackgroundTaskWithExpirationHandler:^
{
// Clean up any unfinished task business by marking where you
// stopped or ending the task outright.
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];

// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
{
// Do the work associated with the task, preferably in chunks.
[self cleanDisk];

[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
});
}

- (unsigned long long)getSize
{
unsigned long long size = 0;
NSDirectoryEnumerator *fileEnumerator = [[NSFileManager defaultManager] enumeratorAtPath:self.diskCachePath];
Expand Down Expand Up @@ -448,7 +488,7 @@ - (void)calculateSizeWithCompletionBlock:(void (^)(NSUInteger fileCount, unsigne

if (completionBlock)
{
dispatch_async(dispatch_get_main_queue(), ^
dispatch_main_sync_safe(^
{
completionBlock(fileCount, totalSize);
});
Expand Down
10 changes: 10 additions & 0 deletions SDWebImage/SDWebImageCompat.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,13 @@
#endif

extern inline UIImage *SDScaledImageForKey(NSString *key, UIImage *image);

#define dispatch_main_sync_safe(block)\
if ([NSThread isMainThread])\
{\
block();\
}\
else\
{\
dispatch_sync(dispatch_get_main_queue(), block);\
}
2 changes: 1 addition & 1 deletion SDWebImage/SDWebImageDownloader.m
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ - (NSArray *)callbacksForURL:(NSURL *)url
{
callbacksForURL = self.URLCallbacks[url];
});
return callbacksForURL;
return [callbacksForURL copy];
}

- (void)removeCallbacksForURL:(NSURL *)url
Expand Down
6 changes: 4 additions & 2 deletions SDWebImage/SDWebImageDownloaderOperation.m
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,9 @@ - (void)start
[[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStartNotification object:self];

// Make sure to run the runloop in our background thread so it can process downloaded data
CFRunLoopRun();
// 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)
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 10, false);
}
else
{
Expand Down Expand Up @@ -230,7 +232,7 @@ - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
UIImage *scaledImage = [self scaledImageForKey:self.request.URL.absoluteString image:image];
image = [UIImage decodedImageWithImage:scaledImage];
CGImageRelease(partialImageRef);
dispatch_async(dispatch_get_main_queue(), ^
dispatch_main_sync_safe(^
{
if (self.completedBlock)
{
Expand Down
65 changes: 50 additions & 15 deletions SDWebImage/SDWebImageManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ @interface SDWebImageCombinedOperation : NSObject <SDWebImageOperation>

@property (assign, nonatomic, getter = isCancelled) BOOL cancelled;
@property (copy, nonatomic) void (^cancelBlock)();
@property (strong, nonatomic) NSOperation *cacheOperation;

@end

Expand Down Expand Up @@ -93,8 +94,11 @@ - (NSString *)cacheKeyForURL:(NSURL *)url
{
if (completedBlock)
{
NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorFileDoesNotExist userInfo:nil];
completedBlock(nil, error, SDImageCacheTypeNone, YES);
dispatch_main_sync_safe(^
{
NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorFileDoesNotExist userInfo:nil];
completedBlock(nil, error, SDImageCacheTypeNone, YES);
});
}
return operation;
}
Expand All @@ -105,17 +109,28 @@ - (NSString *)cacheKeyForURL:(NSURL *)url
}
NSString *key = [self cacheKeyForURL:url];

[self.imageCache queryDiskCacheForKey:key done:^(UIImage *image, SDImageCacheType cacheType)
operation.cacheOperation = [self.imageCache queryDiskCacheForKey:key done:^(UIImage *image, SDImageCacheType cacheType)
{
if (operation.isCancelled) return;
if (operation.isCancelled)
{
@synchronized(self.runningOperations)
{
[self.runningOperations removeObject:operation];
}

return;
}

if ((!image || options & SDWebImageRefreshCached) && (![self.delegate respondsToSelector:@selector(imageManager:shouldDownloadImageForURL:)] || [self.delegate imageManager:self shouldDownloadImageForURL:url]))
{
if (image && options & SDWebImageRefreshCached)
{
// If image was found in the cache bug SDWebImageRefreshCached is provided, notify about the cached image
// AND try to re-download it in order to let a chance to NSURLCache to refresh it from server.
completedBlock(image, nil, cacheType, YES);
dispatch_main_sync_safe(^
{
// If image was found in the cache bug SDWebImageRefreshCached is provided, notify about the cached image
// AND try to re-download it in order to let a chance to NSURLCache to refresh it from server.
completedBlock(image, nil, cacheType, YES);
});
}

// download if no image or requested to refresh anyway, and download allowed by delegate
Expand All @@ -130,15 +145,21 @@ - (NSString *)cacheKeyForURL:(NSURL *)url
// ignore image read from NSURLCache if image if cached but force refreshing
downloaderOptions |= SDWebImageDownloaderIgnoreCachedResponse;
}
__block 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.cancelled)
if (weakOperation.isCancelled)
{
completedBlock(nil, nil, SDImageCacheTypeNone, finished);
dispatch_main_sync_safe(^
{
completedBlock(nil, nil, SDImageCacheTypeNone, finished);
});
}
else if (error)
{
completedBlock(nil, error, SDImageCacheTypeNone, finished);
dispatch_main_sync_safe(^
{
completedBlock(nil, error, SDImageCacheTypeNone, finished);
});

if (error.code != NSURLErrorNotConnectedToInternet)
{
Expand All @@ -163,7 +184,7 @@ - (NSString *)cacheKeyForURL:(NSURL *)url
{
UIImage *transformedImage = [self.delegate imageManager:self transformDownloadedImage:downloadedImage withURL:url];

dispatch_async(dispatch_get_main_queue(), ^
dispatch_main_sync_safe(^
{
completedBlock(transformedImage, nil, SDImageCacheTypeNone, finished);
});
Expand All @@ -177,7 +198,10 @@ - (NSString *)cacheKeyForURL:(NSURL *)url
}
else
{
completedBlock(downloadedImage, nil, SDImageCacheTypeNone, finished);
dispatch_main_sync_safe(^
{
completedBlock(downloadedImage, nil, SDImageCacheTypeNone, finished);
});

if (downloadedImage && finished)
{
Expand All @@ -198,7 +222,10 @@ - (NSString *)cacheKeyForURL:(NSURL *)url
}
else if (image)
{
completedBlock(image, nil, cacheType, YES);
dispatch_main_sync_safe(^
{
completedBlock(image, nil, cacheType, YES);
});
@synchronized(self.runningOperations)
{
[self.runningOperations removeObject:operation];
Expand All @@ -207,7 +234,10 @@ - (NSString *)cacheKeyForURL:(NSURL *)url
else
{
// Image not in cache and download disallowed by delegate
completedBlock(nil, nil, SDImageCacheTypeNone, YES);
dispatch_main_sync_safe(^
{
completedBlock(nil, nil, SDImageCacheTypeNone, YES);
});
@synchronized(self.runningOperations)
{
[self.runningOperations removeObject:operation];
Expand Down Expand Up @@ -251,6 +281,11 @@ - (void)setCancelBlock:(void (^)())cancelBlock
- (void)cancel
{
self.cancelled = YES;
if (self.cacheOperation)
{
[self.cacheOperation cancel];
self.cacheOperation = nil;
}
if (self.cancelBlock)
{
self.cancelBlock();
Expand Down
Loading

0 comments on commit ce3f46e

Please sign in to comment.