From dec0c5fe68c6f51f928dcd67c7ce133f8e890751 Mon Sep 17 00:00:00 2001 From: Patrick Hughes Date: Wed, 8 Aug 2012 19:35:51 -0400 Subject: [PATCH] Added a block based interface to ZSAssetManager. Added an AFNetworking-like category to UIImageView that uses ZSAssetManager. --- UIImageView+ZSAssetManagerAdditions.h | 16 ++++++++ UIImageView+ZSAssetManagerAdditions.m | 29 ++++++++++++++ ZSAssetManager.h | 5 +++ ZSAssetManager.m | 55 ++++++++++++++++++++++----- 4 files changed, 96 insertions(+), 9 deletions(-) create mode 100644 UIImageView+ZSAssetManagerAdditions.h create mode 100644 UIImageView+ZSAssetManagerAdditions.m diff --git a/UIImageView+ZSAssetManagerAdditions.h b/UIImageView+ZSAssetManagerAdditions.h new file mode 100644 index 0000000..c6e969e --- /dev/null +++ b/UIImageView+ZSAssetManagerAdditions.h @@ -0,0 +1,16 @@ +// +// UIImage+ZSAssetManagerAdditions.h +// iPad12 +// +// Created by Patrick Hughes on 8/8/12. +// Copyright (c) 2012 Empirical Development LLC. All rights reserved. +// + +#import + +@interface UIImageView (ZSAssetManagerAdditions) + +- (void)setImageWithURL:(NSURL *)url; +- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholderImage; + +@end diff --git a/UIImageView+ZSAssetManagerAdditions.m b/UIImageView+ZSAssetManagerAdditions.m new file mode 100644 index 0000000..5ae939d --- /dev/null +++ b/UIImageView+ZSAssetManagerAdditions.m @@ -0,0 +1,29 @@ +// +// UIImage+ZSAssetManagerAdditions.m +// iPad12 +// +// Created by Patrick Hughes on 8/8/12. +// Copyright (c) 2012 Empirical Development LLC. All rights reserved. +// + +#import "UIImageView+ZSAssetManagerAdditions.h" +#import "ZSAssetManager.h" + +@implementation UIImageView (ZSAssetManagerAdditions) + +- (void)setImageWithURL:(NSURL *)url +{ + [[ZSAssetManager sharedAssetManager] fetchImageForURL:url withCompletionBlock:^(NSURL *fetchedUrl, UIImage *image) { + if ([url isEqual:fetchedUrl]) { + self.image = image; + } + }]; +} + +- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholderImage +{ + self.image = placeholderImage; + [self setImageWithURL:url]; +} + +@end diff --git a/ZSAssetManager.h b/ZSAssetManager.h index 647262a..122ab80 100755 --- a/ZSAssetManager.h +++ b/ZSAssetManager.h @@ -35,10 +35,15 @@ @class ZSURLConnectionDelegate; +typedef void (^ZDSImageDeliveryBlock)(NSURL *url, UIImage *image); + @interface ZSAssetManager : NSObject @property (nonatomic, assign, getter=allowBackgroundCaching) BOOL backgroundCaching; ++ (ZSAssetManager*)sharedAssetManager; + +- (void)fetchImageForURL:(NSURL*)url withCompletionBlock:(ZDSImageDeliveryBlock)completion; - (UIImage*)imageForURL:(NSURL*)url; - (NSURL*)localURLForAssetURL:(NSURL*)url; diff --git a/ZSAssetManager.m b/ZSAssetManager.m index bde2773..d818cce 100755 --- a/ZSAssetManager.m +++ b/ZSAssetManager.m @@ -67,6 +67,7 @@ - (NSOperationQueue*)assetQueue; @property (nonatomic, assign) NSInteger numberOfItemsDownloaded; @property (nonatomic, retain) NSMutableArray *pendingCacheItems; +@property (nonatomic, retain) NSMutableDictionary *completionBlocks; @end @@ -78,6 +79,19 @@ @implementation ZSAssetManager @synthesize cachePopulationIdentifier; @synthesize currentNetworkState; @synthesize numberOfItemsDownloaded; +@synthesize completionBlocks; + ++ (ZSAssetManager*)sharedAssetManager +{ + static dispatch_once_t onceToken; + static ZSAssetManager *sharedInstance = nil; + + dispatch_once(&onceToken, ^{ + sharedInstance = [[ZSAssetManager alloc] init]; + }); + + return sharedInstance; +} - (id)init { @@ -90,6 +104,7 @@ - (id)init [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(enteringBackground:) name:UIApplicationDidEnterBackgroundNotification object:[UIApplication sharedApplication]]; [self performSelector:@selector(loadPersistentCacheLists) withObject:nil afterDelay:1.0]; + [self setCompletionBlocks:[NSMutableDictionary dictionary]]; return self; } @@ -227,7 +242,6 @@ - (void)loadPersistentCacheLists DLog(@"reinstating cache list ------------------------------------------ %i", [cacheItems count]); [self queueAssetsForRetrievalFromURLSet:assetSet]; - MCRelease(assetSet); } } @@ -242,7 +256,6 @@ - (void)persistCacheList:(NSSet*)set } ZAssert([array writeToFile:filePath atomically:NO], @"Failed to write cache list to disk"); - MCRelease(array); } - (void)calculateBandwidthForDelegate:(ZSURLConnectionDelegate*)delegate @@ -309,7 +322,7 @@ - (void)cacheOperationCompleted:(ZSURLConnectionDelegate*)delegate - (void)cacheOperationFailed:(ZSURLConnectionDelegate*)delegate { - if (VERBOSE) DLog(@"%@:%s request failed", [self class], _cmd); + if (VERBOSE) DLog(@"request failed"); } #pragma mark - @@ -363,8 +376,6 @@ - (void)downloadImage:(NSURL*)url [delegate setQueuePriority:NSOperationQueuePriorityNormal]; [[self assetQueue] addOperation:delegate]; - - MCRelease(delegate); } #pragma mark - @@ -376,8 +387,21 @@ - (void)dataReceived:(ZSURLConnectionDelegate*)delegate if (VERBOSE) DLog(@"%s zero-length image received; ignoring", __PRETTY_FUNCTION__); return; } + NSURL *url = [delegate myURL]; + UIImage *image = [self imageForURL:url]; + + // Fire off any completion blocks we may have. + if ([[self completionBlocks] objectForKey:url]) { + NSMutableArray *blocks = [[self completionBlocks] objectForKey:url]; + for (ZDSImageDeliveryBlock completionBlock in blocks) { + completionBlock(url, image); + } + + // We don't need you any more. + [[self completionBlocks] removeObjectForKey:url]; + } - NSNotification *notification = [NSNotification notificationWithName:kImageDownloadComplete object:[delegate myURL] userInfo:nil]; + NSNotification *notification = [NSNotification notificationWithName:kImageDownloadComplete object:url userInfo:nil]; [[NSNotificationQueue defaultQueue] enqueueNotification:notification postingStyle:NSPostWhenIdle coalesceMask:NSNotificationCoalescingOnSender forModes:nil]; @@ -386,7 +410,7 @@ - (void)dataReceived:(ZSURLConnectionDelegate*)delegate - (void)requestFailedForDelegate:(ZSURLConnectionDelegate*)delegate { - if (VERBOSE) DLog(@"%@:%s request failed", [self class], _cmd); + if (VERBOSE) DLog(@"request failed"); if (!delegate) return; } @@ -419,7 +443,6 @@ - (void)queueAssetForRetrievalFromURL:(NSURL*)url [cacheOperation setThreadPriority:0.0f]; [[self assetQueue] addOperation:cacheOperation]; - MCRelease(cacheOperation); } - (void)queueAssetsForRetrievalFromURLSet:(NSSet*)urlSet @@ -471,6 +494,20 @@ - (NSURL*)localURLForAssetURL:(NSURL*)url return nil; } +- (void)fetchImageForURL:(NSURL*)url withCompletionBlock:(ZDSImageDeliveryBlock)completion +{ + UIImage *image = [self imageForURL:url]; + + if (image) { + completion(url, image); + } + else { + NSMutableArray *array = [NSMutableArray arrayWithArray:[[self completionBlocks] objectForKey:url]]; + [array addObject:[completion copy]]; + [[self completionBlocks] setObject:array forKey:url]; + } +} + - (UIImage*)imageForURL:(NSURL*)url { ZAssert(url, @"nil URL passed again"); @@ -506,7 +543,7 @@ - (void)clearCaches NSFileManager *fileManager = [NSFileManager defaultManager]; NSError *error = nil; - NSString *tempCachePath = [NSString stringWithFormat:@"%@%u", [self cachePath], [NSDate timeIntervalSinceReferenceDate]]; + NSString *tempCachePath = [NSString stringWithFormat:@"%@ %.2f", [self cachePath], [NSDate timeIntervalSinceReferenceDate]]; ZAssert([fileManager moveItemAtPath:[self cachePath] toPath:tempCachePath error:&error], @"Move failed"); DLog(@"move directory: %.2f", ([NSDate timeIntervalSinceReferenceDate] - start)); dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);