Merge pull request #996 from harishkashyap/fix-memory-issues
Adds option to decompress images and select prefetcher Queue
Showing
8 changed files
with
37 additions
and
5 deletions
@@ -37,6 +37,12 @@ typedef void(^SDWebImageCalculateSizeBlock)(NSUInteger fileCount, NSUInteger tot | @@ -37,6 +37,12 @@ typedef void(^SDWebImageCalculateSizeBlock)(NSUInteger fileCount, NSUInteger tot | ||
37 | @interface SDImageCache : NSObject | 37 | @interface SDImageCache : NSObject |
38 | 38 | ||
39 | /** | 39 | /** |
40 | + * Decompressing images that are downloaded and cached can improve peformance but can consume lot of memory. | ||
41 | + * Defaults to YES. Set this to NO if you are experiencing a crash due to excessive memory consumption. | ||
42 | + */ | ||
43 | +@property (assign, nonatomic) BOOL shouldDecompressImages; | ||
44 | + | ||
45 | +/** | ||
40 | * The maximum "total cost" of the in-memory image cache. The cost function is the number of pixels held in memory. | 46 | * The maximum "total cost" of the in-memory image cache. The cost function is the number of pixels held in memory. |
41 | */ | 47 | */ |
42 | @property (assign, nonatomic) NSUInteger maxMemoryCost; | 48 | @property (assign, nonatomic) NSUInteger maxMemoryCost; |
@@ -77,6 +77,9 @@ BOOL ImageDataHasPNGPreffix(NSData *data) { | @@ -77,6 +77,9 @@ BOOL ImageDataHasPNGPreffix(NSData *data) { | ||
77 | NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); | 77 | NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); |
78 | _diskCachePath = [paths[0] stringByAppendingPathComponent:fullNamespace]; | 78 | _diskCachePath = [paths[0] stringByAppendingPathComponent:fullNamespace]; |
79 | 79 | ||
80 | + // Set decompression to YES | ||
81 | + _shouldDecompressImages = YES; | ||
82 | + | ||
80 | dispatch_sync(_ioQueue, ^{ | 83 | dispatch_sync(_ioQueue, ^{ |
81 | _fileManager = [NSFileManager new]; | 84 | _fileManager = [NSFileManager new]; |
82 | }); | 85 | }); |
@@ -266,7 +269,9 @@ BOOL ImageDataHasPNGPreffix(NSData *data) { | @@ -266,7 +269,9 @@ BOOL ImageDataHasPNGPreffix(NSData *data) { | ||
266 | if (data) { | 269 | if (data) { |
267 | UIImage *image = [UIImage sd_imageWithData:data]; | 270 | UIImage *image = [UIImage sd_imageWithData:data]; |
268 | image = [self scaledImageForKey:key image:image]; | 271 | image = [self scaledImageForKey:key image:image]; |
272 | + if (self.shouldDecompressImages) { | ||
269 | image = [UIImage decodedImageWithImage:image]; | 273 | image = [UIImage decodedImageWithImage:image]; |
274 | + } | ||
270 | return image; | 275 | return image; |
271 | } | 276 | } |
272 | else { | 277 | else { |
@@ -49,8 +49,6 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageDownloaderOptions) { | @@ -49,8 +49,6 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageDownloaderOptions) { | ||
49 | * Put the image in the high priority queue. | 49 | * Put the image in the high priority queue. |
50 | */ | 50 | */ |
51 | SDWebImageDownloaderHighPriority = 1 << 7, | 51 | SDWebImageDownloaderHighPriority = 1 << 7, |
52 | - | ||
53 | - | ||
54 | }; | 52 | }; |
55 | 53 | ||
56 | typedef NS_ENUM(NSInteger, SDWebImageDownloaderExecutionOrder) { | 54 | typedef NS_ENUM(NSInteger, SDWebImageDownloaderExecutionOrder) { |
@@ -79,12 +77,17 @@ typedef NSDictionary *(^SDWebImageDownloaderHeadersFilterBlock)(NSURL *url, NSDi | @@ -79,12 +77,17 @@ typedef NSDictionary *(^SDWebImageDownloaderHeadersFilterBlock)(NSURL *url, NSDi | ||
79 | */ | 77 | */ |
80 | @interface SDWebImageDownloader : NSObject | 78 | @interface SDWebImageDownloader : NSObject |
81 | 79 | ||
80 | +/** | ||
81 | + * Decompressing images that are downloaded and cached can improve peformance but can consume lot of memory. | ||
82 | + * Defaults to YES. Set this to NO if you are experiencing a crash due to excessive memory consumption. | ||
83 | + */ | ||
84 | +@property (assign, nonatomic) BOOL shouldDecompressImages; | ||
85 | + | ||
82 | @property (assign, nonatomic) NSInteger maxConcurrentDownloads; | 86 | @property (assign, nonatomic) NSInteger maxConcurrentDownloads; |
83 | 87 | ||
84 | /** | 88 | /** |
85 | * Shows the current amount of downloads that still need to be downloaded | 89 | * Shows the current amount of downloads that still need to be downloaded |
86 | */ | 90 | */ |
87 | - | ||
88 | @property (readonly, nonatomic) NSUInteger currentDownloadCount; | 91 | @property (readonly, nonatomic) NSUInteger currentDownloadCount; |
89 | 92 | ||
90 | 93 |
@@ -65,6 +65,7 @@ static NSString *const kCompletedCallbackKey = @"completed"; | @@ -65,6 +65,7 @@ static NSString *const kCompletedCallbackKey = @"completed"; | ||
65 | - (id)init { | 65 | - (id)init { |
66 | if ((self = [super init])) { | 66 | if ((self = [super init])) { |
67 | _operationClass = [SDWebImageDownloaderOperation class]; | 67 | _operationClass = [SDWebImageDownloaderOperation class]; |
68 | + _shouldDecompressImages = YES; | ||
68 | _executionOrder = SDWebImageDownloaderFIFOExecutionOrder; | 69 | _executionOrder = SDWebImageDownloaderFIFOExecutionOrder; |
69 | _downloadQueue = [NSOperationQueue new]; | 70 | _downloadQueue = [NSOperationQueue new]; |
70 | _downloadQueue.maxConcurrentOperationCount = 6; | 71 | _downloadQueue.maxConcurrentOperationCount = 6; |
@@ -166,6 +167,7 @@ static NSString *const kCompletedCallbackKey = @"completed"; | @@ -166,6 +167,7 @@ static NSString *const kCompletedCallbackKey = @"completed"; | ||
166 | [sself.URLCallbacks removeObjectForKey:url]; | 167 | [sself.URLCallbacks removeObjectForKey:url]; |
167 | }); | 168 | }); |
168 | }]; | 169 | }]; |
170 | + operation.shouldDecompressImages = wself.shouldDecompressImages; | ||
169 | 171 | ||
170 | if (wself.username && wself.password) { | 172 | if (wself.username && wself.password) { |
171 | operation.credential = [NSURLCredential credentialWithUser:wself.username password:wself.password persistence:NSURLCredentialPersistenceForSession]; | 173 | operation.credential = [NSURLCredential credentialWithUser:wself.username password:wself.password persistence:NSURLCredentialPersistenceForSession]; |
@@ -17,6 +17,9 @@ | @@ -17,6 +17,9 @@ | ||
17 | */ | 17 | */ |
18 | @property (strong, nonatomic, readonly) NSURLRequest *request; | 18 | @property (strong, nonatomic, readonly) NSURLRequest *request; |
19 | 19 | ||
20 | + | ||
21 | +@property (assign, nonatomic) BOOL shouldDecompressImages; | ||
22 | + | ||
20 | /** | 23 | /** |
21 | * Whether the URL connection should consult the credential storage for authenticating the connection. `YES` by default. | 24 | * Whether the URL connection should consult the credential storage for authenticating the connection. `YES` by default. |
22 | * | 25 | * |
@@ -47,6 +47,7 @@ | @@ -47,6 +47,7 @@ | ||
47 | cancelled:(SDWebImageNoParamsBlock)cancelBlock { | 47 | cancelled:(SDWebImageNoParamsBlock)cancelBlock { |
48 | if ((self = [super init])) { | 48 | if ((self = [super init])) { |
49 | _request = request; | 49 | _request = request; |
50 | + _shouldDecompressImages = YES; | ||
50 | _shouldUseCredentialStorage = YES; | 51 | _shouldUseCredentialStorage = YES; |
51 | _options = options; | 52 | _options = options; |
52 | _progressBlock = [progressBlock copy]; | 53 | _progressBlock = [progressBlock copy]; |
@@ -294,7 +295,12 @@ | @@ -294,7 +295,12 @@ | ||
294 | UIImage *image = [UIImage imageWithCGImage:partialImageRef scale:1 orientation:orientation]; | 295 | UIImage *image = [UIImage imageWithCGImage:partialImageRef scale:1 orientation:orientation]; |
295 | NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:self.request.URL]; | 296 | NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:self.request.URL]; |
296 | UIImage *scaledImage = [self scaledImageForKey:key image:image]; | 297 | UIImage *scaledImage = [self scaledImageForKey:key image:image]; |
298 | + if (self.shouldDecompressImages) { | ||
297 | image = [UIImage decodedImageWithImage:scaledImage]; | 299 | image = [UIImage decodedImageWithImage:scaledImage]; |
300 | + } | ||
301 | + else { | ||
302 | + image = scaledImage; | ||
303 | + } | ||
298 | CGImageRelease(partialImageRef); | 304 | CGImageRelease(partialImageRef); |
299 | dispatch_main_sync_safe(^{ | 305 | dispatch_main_sync_safe(^{ |
300 | if (self.completedBlock) { | 306 | if (self.completedBlock) { |
@@ -365,8 +371,10 @@ | @@ -365,8 +371,10 @@ | ||
365 | 371 | ||
366 | // Do not force decoding animated GIFs | 372 | // Do not force decoding animated GIFs |
367 | if (!image.images) { | 373 | if (!image.images) { |
374 | + if (self.shouldDecompressImages) { | ||
368 | image = [UIImage decodedImageWithImage:image]; | 375 | image = [UIImage decodedImageWithImage:image]; |
369 | } | 376 | } |
377 | + } | ||
370 | if (CGSizeEqualToSize(image.size, CGSizeZero)) { | 378 | if (CGSizeEqualToSize(image.size, CGSizeZero)) { |
371 | completionBlock(nil, nil, [NSError errorWithDomain:@"SDWebImageErrorDomain" code:0 userInfo:@{NSLocalizedDescriptionKey : @"Downloaded image has 0 pixels"}], YES); | 379 | completionBlock(nil, nil, [NSError errorWithDomain:@"SDWebImageErrorDomain" code:0 userInfo:@{NSLocalizedDescriptionKey : @"Downloaded image has 0 pixels"}], YES); |
372 | } | 380 | } |
@@ -58,6 +58,11 @@ typedef void(^SDWebImagePrefetcherCompletionBlock)(NSUInteger noOfFinishedUrls, | @@ -58,6 +58,11 @@ typedef void(^SDWebImagePrefetcherCompletionBlock)(NSUInteger noOfFinishedUrls, | ||
58 | */ | 58 | */ |
59 | @property (nonatomic, assign) SDWebImageOptions options; | 59 | @property (nonatomic, assign) SDWebImageOptions options; |
60 | 60 | ||
61 | +/** | ||
62 | + * Queue options for Prefetcher. Defaults to Main Queue. | ||
63 | + */ | ||
64 | +@property (nonatomic, assign) dispatch_queue_t prefetcherQueue; | ||
65 | + | ||
61 | @property (weak, nonatomic) id <SDWebImagePrefetcherDelegate> delegate; | 66 | @property (weak, nonatomic) id <SDWebImagePrefetcherDelegate> delegate; |
62 | 67 | ||
63 | /** | 68 | /** |
@@ -40,6 +40,7 @@ | @@ -40,6 +40,7 @@ | ||
40 | if ((self = [super init])) { | 40 | if ((self = [super init])) { |
41 | _manager = [SDWebImageManager new]; | 41 | _manager = [SDWebImageManager new]; |
42 | _options = SDWebImageLowPriority; | 42 | _options = SDWebImageLowPriority; |
43 | + _prefetcherQueue = dispatch_get_main_queue(); | ||
43 | self.maxConcurrentDownloads = 3; | 44 | self.maxConcurrentDownloads = 3; |
44 | } | 45 | } |
45 | return self; | 46 | return self; |
@@ -82,9 +83,8 @@ | @@ -82,9 +83,8 @@ | ||
82 | totalCount:self.prefetchURLs.count | 83 | totalCount:self.prefetchURLs.count |
83 | ]; | 84 | ]; |
84 | } | 85 | } |
85 | - | ||
86 | if (self.prefetchURLs.count > self.requestedCount) { | 86 | if (self.prefetchURLs.count > self.requestedCount) { |
87 | - dispatch_async(dispatch_get_main_queue(), ^{ | 87 | + dispatch_async(self.prefetcherQueue, ^{ |
88 | [self startPrefetchingAtIndex:self.requestedCount]; | 88 | [self startPrefetchingAtIndex:self.requestedCount]; |
89 | }); | 89 | }); |
90 | } | 90 | } |
-
Please register or login to post a comment