diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index fec206adb5..e6a8490473 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -230,6 +230,8 @@ AC47D9451B3BB41900AAEE9D /* ASRelativeSize.h in Headers */ = {isa = PBXBuildFile; fileRef = AC47D9431B3BB41900AAEE9D /* ASRelativeSize.h */; settings = {ATTRIBUTES = (Public, ); }; }; AC47D9461B3BB41900AAEE9D /* ASRelativeSize.mm in Sources */ = {isa = PBXBuildFile; fileRef = AC47D9441B3BB41900AAEE9D /* ASRelativeSize.mm */; }; AC6456091B0A335000CF11B8 /* ASCellNode.m in Sources */ = {isa = PBXBuildFile; fileRef = AC6456071B0A335000CF11B8 /* ASCellNode.m */; }; + ACC945A91BA9E7A0005E1FB8 /* ASViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = ACC945A81BA9E7A0005E1FB8 /* ASViewController.h */; }; + ACC945AB1BA9E7C1005E1FB8 /* ASViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = ACC945AA1BA9E7C1005E1FB8 /* ASViewController.m */; }; ACF6ED1A1B17843500DA7C62 /* ASBackgroundLayoutSpec.h in Headers */ = {isa = PBXBuildFile; fileRef = ACF6ED011B17843500DA7C62 /* ASBackgroundLayoutSpec.h */; settings = {ATTRIBUTES = (Public, ); }; }; ACF6ED1B1B17843500DA7C62 /* ASBackgroundLayoutSpec.mm in Sources */ = {isa = PBXBuildFile; fileRef = ACF6ED021B17843500DA7C62 /* ASBackgroundLayoutSpec.mm */; }; ACF6ED1C1B17843500DA7C62 /* ASCenterLayoutSpec.h in Headers */ = {isa = PBXBuildFile; fileRef = ACF6ED031B17843500DA7C62 /* ASCenterLayoutSpec.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -574,6 +576,8 @@ AC47D9431B3BB41900AAEE9D /* ASRelativeSize.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASRelativeSize.h; path = AsyncDisplayKit/Layout/ASRelativeSize.h; sourceTree = ""; }; AC47D9441B3BB41900AAEE9D /* ASRelativeSize.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ASRelativeSize.mm; path = AsyncDisplayKit/Layout/ASRelativeSize.mm; sourceTree = ""; }; AC6456071B0A335000CF11B8 /* ASCellNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASCellNode.m; sourceTree = ""; }; + ACC945A81BA9E7A0005E1FB8 /* ASViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASViewController.h; sourceTree = ""; }; + ACC945AA1BA9E7C1005E1FB8 /* ASViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASViewController.m; sourceTree = ""; }; ACF6ED011B17843500DA7C62 /* ASBackgroundLayoutSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASBackgroundLayoutSpec.h; path = AsyncDisplayKit/Layout/ASBackgroundLayoutSpec.h; sourceTree = ""; }; ACF6ED021B17843500DA7C62 /* ASBackgroundLayoutSpec.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; name = ASBackgroundLayoutSpec.mm; path = AsyncDisplayKit/Layout/ASBackgroundLayoutSpec.mm; sourceTree = ""; }; ACF6ED031B17843500DA7C62 /* ASCenterLayoutSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASCenterLayoutSpec.h; path = AsyncDisplayKit/Layout/ASCenterLayoutSpec.h; sourceTree = ""; }; @@ -758,6 +762,8 @@ 0574D5E119C110610097DC25 /* ASTableViewProtocols.h */, 058D09DF195D050800B7D73C /* ASTextNode.h */, 058D09E0195D050800B7D73C /* ASTextNode.mm */, + ACC945A81BA9E7A0005E1FB8 /* ASViewController.h */, + ACC945AA1BA9E7C1005E1FB8 /* ASViewController.m */, 6BDC61F51978FEA400E50D21 /* AsyncDisplayKit.h */, 058D09E1195D050800B7D73C /* Details */, 058D0A01195D050800B7D73C /* Private */, @@ -1114,6 +1120,7 @@ 058D0A63195D05DC00B7D73C /* ASTextNodeTypes.h in Headers */, 058D0A64195D05DC00B7D73C /* ASTextNodeWordKerner.h in Headers */, 058D0A81195D05F900B7D73C /* ASThread.h in Headers */, + ACC945A91BA9E7A0005E1FB8 /* ASViewController.h in Headers */, 6BDC61F61979037800E50D21 /* AsyncDisplayKit.h in Headers */, 205F0E211B376416007741D0 /* CGRect+ASConvenience.h in Headers */, 058D0A66195D05DC00B7D73C /* NSMutableAttributedString+TextKitAdditions.h in Headers */, @@ -1478,6 +1485,7 @@ 058D0A1E195D050800B7D73C /* ASTextNodeShadower.m in Sources */, 058D0A1F195D050800B7D73C /* ASTextNodeTextKitHelpers.mm in Sources */, 058D0A20195D050800B7D73C /* ASTextNodeWordKerner.m in Sources */, + ACC945AB1BA9E7C1005E1FB8 /* ASViewController.m in Sources */, 205F0E221B376416007741D0 /* CGRect+ASConvenience.m in Sources */, 058D0A21195D050800B7D73C /* NSMutableAttributedString+TextKitAdditions.m in Sources */, 205F0E101B371875007741D0 /* UICollectionViewLayout+ASConvenience.m in Sources */, diff --git a/AsyncDisplayKit/ASViewController.h b/AsyncDisplayKit/ASViewController.h new file mode 100644 index 0000000000..7be26d5916 --- /dev/null +++ b/AsyncDisplayKit/ASViewController.h @@ -0,0 +1,18 @@ +// +// ASViewController.h +// AsyncDisplayKit +// +// Created by Huy Nguyen on 16/09/15. +// Copyright (c) 2015 Facebook. All rights reserved. +// + +#import +#import + +@interface ASViewController : UIViewController + +@property (nonatomic, strong, readonly) ASDisplayNode *node; + +- (instancetype)initWithNode:(ASDisplayNode *)node; + +@end \ No newline at end of file diff --git a/AsyncDisplayKit/ASViewController.m b/AsyncDisplayKit/ASViewController.m new file mode 100644 index 0000000000..6645198398 --- /dev/null +++ b/AsyncDisplayKit/ASViewController.m @@ -0,0 +1,47 @@ +// +// ASViewController.m +// AsyncDisplayKit +// +// Created by Huy Nguyen on 16/09/15. +// Copyright (c) 2015 Facebook. All rights reserved. +// + +#import "ASViewController.h" +#import "ASAssert.h" +#import "ASDimension.h" + +@implementation ASViewController + +- (instancetype)initWithNode:(ASDisplayNode *)node +{ + if (!(self = [super init])) { + return nil; + } + + ASDisplayNodeAssertNotNil(node, @"Node must not be nil"); + ASDisplayNodeAssertTrue(!node.layerBacked); + _node = node; + + return self; +} + +- (void)loadView +{ + ASDisplayNodeAssertTrue(!_node.layerBacked); + self.view = _node.view; +} + +- (void)viewWillLayoutSubviews +{ + ASSizeRange constrainedSize = ASSizeRangeMake(self.view.bounds.size, self.view.bounds.size); + [_node measureWithSizeRange:constrainedSize]; + [super viewWillLayoutSubviews]; +} + +- (void)viewWillAppear:(BOOL)animated +{ + [super viewWillAppear:animated]; + [_node recursivelyFetchData]; +} + +@end diff --git a/AsyncDisplayKit/AsyncDisplayKit.h b/AsyncDisplayKit/AsyncDisplayKit.h index fef5761c7b..6b2aa9ea9d 100644 --- a/AsyncDisplayKit/AsyncDisplayKit.h +++ b/AsyncDisplayKit/AsyncDisplayKit.h @@ -26,6 +26,8 @@ #import +#import + #import #import #import diff --git a/examples/Multiplex/Sample.xcodeproj/project.pbxproj b/examples/Multiplex/Sample.xcodeproj/project.pbxproj index a1a1bd3d35..1383d38552 100644 --- a/examples/Multiplex/Sample.xcodeproj/project.pbxproj +++ b/examples/Multiplex/Sample.xcodeproj/project.pbxproj @@ -14,6 +14,7 @@ 3EC0CDCBA10D483D9F386E5E /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3D24B17D1E4A4E7A9566C5E9 /* libPods.a */; }; 6C2C82AC19EE274300767484 /* Default-667h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 6C2C82AA19EE274300767484 /* Default-667h@2x.png */; }; 6C2C82AD19EE274300767484 /* Default-736h@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 6C2C82AB19EE274300767484 /* Default-736h@3x.png */; }; + ACC945AE1BA9EFBA005E1FB8 /* ScreenNode.m in Sources */ = {isa = PBXBuildFile; fileRef = ACC945AD1BA9EFBA005E1FB8 /* ScreenNode.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -29,6 +30,8 @@ 3D24B17D1E4A4E7A9566C5E9 /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; }; 6C2C82AA19EE274300767484 /* Default-667h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-667h@2x.png"; sourceTree = SOURCE_ROOT; }; 6C2C82AB19EE274300767484 /* Default-736h@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-736h@3x.png"; sourceTree = SOURCE_ROOT; }; + ACC945AC1BA9EFB3005E1FB8 /* ScreenNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ScreenNode.h; sourceTree = ""; }; + ACC945AD1BA9EFBA005E1FB8 /* ScreenNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ScreenNode.m; sourceTree = ""; }; C068F1D3F0CC317E895FCDAB /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -72,6 +75,8 @@ 05E2128919D4DB510098F589 /* AppDelegate.m */, 05E2128B19D4DB510098F589 /* ViewController.h */, 05E2128C19D4DB510098F589 /* ViewController.m */, + ACC945AC1BA9EFB3005E1FB8 /* ScreenNode.h */, + ACC945AD1BA9EFBA005E1FB8 /* ScreenNode.m */, 05E2128419D4DB510098F589 /* Supporting Files */, ); path = Sample; @@ -214,6 +219,7 @@ 05E2128D19D4DB510098F589 /* ViewController.m in Sources */, 05E2128A19D4DB510098F589 /* AppDelegate.m in Sources */, 05E2128719D4DB510098F589 /* main.m in Sources */, + ACC945AE1BA9EFBA005E1FB8 /* ScreenNode.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/examples/Multiplex/Sample/ScreenNode.h b/examples/Multiplex/Sample/ScreenNode.h new file mode 100644 index 0000000000..38ea2e63cb --- /dev/null +++ b/examples/Multiplex/Sample/ScreenNode.h @@ -0,0 +1,19 @@ +// +// ScreenNode.h +// Sample +// +// Created by Huy Nguyen on 16/09/15. +// Copyright (c) 2015 Facebook. All rights reserved. +// + +#import + +@interface ScreenNode : ASDisplayNode + +@property (nonatomic, strong) ASMultiplexImageNode *imageNode; +@property (nonatomic, strong) ASTextNode *textNode; + +- (void)start; +- (void)reload; + +@end \ No newline at end of file diff --git a/examples/Multiplex/Sample/ScreenNode.m b/examples/Multiplex/Sample/ScreenNode.m new file mode 100644 index 0000000000..1032e059eb --- /dev/null +++ b/examples/Multiplex/Sample/ScreenNode.m @@ -0,0 +1,156 @@ +// +// ScreenNode.m +// Sample +// +// Created by Huy Nguyen on 16/09/15. +// Copyright (c) 2015 Facebook. All rights reserved. +// + +#import "ScreenNode.h" +#import "AsyncDisplayKit/AsyncDisplayKit.h" + +@interface ScreenNode() +@end + +@implementation ScreenNode + +- (instancetype)init +{ + if (!(self = [super init])) { + return nil; + } + + // multiplex image node! + // NB: we're using a custom downloader with an artificial delay for this demo, but ASBasicImageDownloader works too! + _imageNode = [[ASMultiplexImageNode alloc] initWithCache:nil downloader:self]; + _imageNode.dataSource = self; + _imageNode.delegate = self; + + // placeholder colour + _imageNode.backgroundColor = ASDisplayNodeDefaultPlaceholderColor(); + + // load low-quality images before high-quality images + _imageNode.downloadsIntermediateImages = YES; + + // simple status label + _textNode = [[ASTextNode alloc] init]; + + [self addSubnode:_imageNode]; + [self addSubnode:_textNode]; + + return self; +} + +- (void)start +{ + [self setText:@"loading…"]; + _textNode.userInteractionEnabled = NO; + _imageNode.imageIdentifiers = @[ @"best", @"medium", @"worst" ]; // go! +} + +- (void)reload { + [self start]; + [_imageNode reloadImageIdentifierSources]; +} + +- (void)setText:(NSString *)text +{ + NSDictionary *attributes = @{NSFontAttributeName: [UIFont fontWithName:@"HelveticaNeue-Light" size:22.0f]}; + NSAttributedString *string = [[NSAttributedString alloc] initWithString:text + attributes:attributes]; + _textNode.attributedString = string; + [self setNeedsLayout]; +} + +- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize +{ + return + [ASInsetLayoutSpec + insetLayoutSpecWithInsets:UIEdgeInsetsMake(10, 10, 10, 10) + child: + [ASStackLayoutSpec + stackLayoutSpecWithDirection:ASStackLayoutDirectionVertical + spacing:10 + justifyContent:ASStackLayoutJustifyContentCenter + alignItems:ASStackLayoutAlignItemsCenter + children:@[[ASRatioLayoutSpec ratioLayoutSpecWithRatio:1 child:_imageNode], _textNode]]]; +} + +#pragma mark - +#pragma mark ASMultiplexImageNode data source & delegate. + +- (NSURL *)multiplexImageNode:(ASMultiplexImageNode *)imageNode URLForImageIdentifier:(id)imageIdentifier +{ + if ([imageIdentifier isEqualToString:@"worst"]) { + return [NSURL URLWithString:@"https://raw.githubusercontent.com/facebook/AsyncDisplayKit/master/examples/Multiplex/worst.png"]; + } + + if ([imageIdentifier isEqualToString:@"medium"]) { + return [NSURL URLWithString:@"https://raw.githubusercontent.com/facebook/AsyncDisplayKit/master/examples/Multiplex/medium.png"]; + } + + if ([imageIdentifier isEqualToString:@"best"]) { + return [NSURL URLWithString:@"https://raw.githubusercontent.com/facebook/AsyncDisplayKit/master/examples/Multiplex/best.png"]; + } + + // unexpected identifier + return nil; +} + +- (void)multiplexImageNode:(ASMultiplexImageNode *)imageNode didFinishDownloadingImageWithIdentifier:(id)imageIdentifier error:(NSError *)error +{ + [self setText:[NSString stringWithFormat:@"loaded '%@'", imageIdentifier]]; + + if ([imageIdentifier isEqualToString:@"best"]) { + [self setText:[_textNode.attributedString.string stringByAppendingString:@". tap to reload"]]; + _textNode.userInteractionEnabled = YES; + } +} + + +#pragma mark - +#pragma mark ASImageDownloaderProtocol. + +- (id)downloadImageWithURL:(NSURL *)URL + callbackQueue:(dispatch_queue_t)callbackQueue + downloadProgressBlock:(void (^)(CGFloat progress))downloadProgressBlock + completion:(void (^)(CGImageRef image, NSError *error))completion +{ + // if no callback queue is supplied, run on the main thread + if (callbackQueue == nil) { + callbackQueue = dispatch_get_main_queue(); + } + + // call completion blocks + void (^handler)(NSURLResponse *, NSData *, NSError *) = ^(NSURLResponse *response, NSData *data, NSError *connectionError) { + // add an artificial delay + usleep(1.0 * USEC_PER_SEC); + + // ASMultiplexImageNode callbacks + dispatch_async(callbackQueue, ^{ + if (downloadProgressBlock) { + downloadProgressBlock(1.0f); + } + + if (completion) { + completion([[UIImage imageWithData:data] CGImage], connectionError); + } + }); + }; + + // let NSURLConnection do the heavy lifting + NSURLRequest *request = [NSURLRequest requestWithURL:URL]; + [NSURLConnection sendAsynchronousRequest:request + queue:[[NSOperationQueue alloc] init] + completionHandler:handler]; + + // return nil, don't support cancellation + return nil; +} + +- (void)cancelImageDownloadForIdentifier:(id)downloadIdentifier +{ + // no-op, don't support cancellation +} + +@end diff --git a/examples/Multiplex/Sample/ViewController.h b/examples/Multiplex/Sample/ViewController.h index d0e9200d88..b73c290852 100644 --- a/examples/Multiplex/Sample/ViewController.h +++ b/examples/Multiplex/Sample/ViewController.h @@ -9,8 +9,8 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#import +#import -@interface ViewController : UIViewController +@interface ViewController : ASViewController @end diff --git a/examples/Multiplex/Sample/ViewController.m b/examples/Multiplex/Sample/ViewController.m index 7af462d91c..b3c5717340 100644 --- a/examples/Multiplex/Sample/ViewController.m +++ b/examples/Multiplex/Sample/ViewController.m @@ -10,77 +10,39 @@ */ #import "ViewController.h" +#import "ScreenNode.h" -#import - - -@interface ViewController () -{ - ASMultiplexImageNode *_imageNode; - - UILabel *_textLabel; +@interface ViewController() { + ScreenNode *_screenNode; } @end - @implementation ViewController - (instancetype)init { - if (!(self = [super init])) + ScreenNode *node = [[ScreenNode alloc] init]; + if (!(self = [super initWithNode:node])) return nil; - - // multiplex image node! - // NB: we're using a custom downloader with an artificial delay for this demo, but ASBasicImageDownloader works too! - _imageNode = [[ASMultiplexImageNode alloc] initWithCache:nil downloader:self]; - _imageNode.dataSource = self; - _imageNode.delegate = self; - - // placeholder colour - _imageNode.backgroundColor = ASDisplayNodeDefaultPlaceholderColor(); - - // load low-quality images before high-quality images - _imageNode.downloadsIntermediateImages = YES; - - - // simple status label - _textLabel = [[UILabel alloc] init]; - _textLabel.textAlignment = NSTextAlignmentCenter; - _textLabel.font = [UIFont fontWithName:@"HelveticaNeue-Light" size:22.0f]; + _screenNode = node; // tap to reload UITapGestureRecognizer *gr = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(reload:)]; - [_textLabel addGestureRecognizer:gr]; - + [_screenNode.textNode.view addGestureRecognizer:gr]; return self; } -- (void)viewDidLoad +- (void)viewWillAppear:(BOOL)animated { - [super viewDidLoad]; - - [self.view addSubnode:_imageNode]; - [self.view addSubview:_textLabel]; - - [self start]; + [super viewWillAppear:animated]; + [_screenNode start]; } -- (void)viewWillLayoutSubviews -{ - static CGFloat padding = 40.0f; - - // lay out image - CGFloat imageWidth = self.view.bounds.size.width - padding; - CGPoint imageOrigin = CGPointMake(roundf((self.view.bounds.size.width - imageWidth) / 2.0f), - roundf((self.view.bounds.size.height - imageWidth) / 2.0f)); - _imageNode.frame = (CGRect){ imageOrigin, CGSizeMake(imageWidth, imageWidth) }; - - // label - CGSize textSize = [_textLabel sizeThatFits:CGSizeMake(self.view.bounds.size.width, FLT_MAX)]; - _textLabel.frame = CGRectMake(0.0f, imageOrigin.y + imageWidth + padding, self.view.bounds.size.width, textSize.height); +- (void)reload:(id)sender { + [_screenNode reload]; } - (BOOL)prefersStatusBarHidden @@ -88,95 +50,4 @@ return YES; } -- (void)start -{ - _textLabel.text = @"loading…"; - _textLabel.userInteractionEnabled = NO; - - _imageNode.imageIdentifiers = @[ @"best", @"medium", @"worst" ]; // go! -} - -- (void)reload:(id)sender { - [self start]; - [_imageNode reloadImageIdentifierSources]; -} - - -#pragma mark - -#pragma mark ASMultiplexImageNode data source & delegate. - -- (NSURL *)multiplexImageNode:(ASMultiplexImageNode *)imageNode URLForImageIdentifier:(id)imageIdentifier -{ - if ([imageIdentifier isEqualToString:@"worst"]) { - return [NSURL URLWithString:@"https://raw.githubusercontent.com/facebook/AsyncDisplayKit/master/examples/Multiplex/worst.png"]; - } - - if ([imageIdentifier isEqualToString:@"medium"]) { - return [NSURL URLWithString:@"https://raw.githubusercontent.com/facebook/AsyncDisplayKit/master/examples/Multiplex/medium.png"]; - } - - if ([imageIdentifier isEqualToString:@"best"]) { - return [NSURL URLWithString:@"https://raw.githubusercontent.com/facebook/AsyncDisplayKit/master/examples/Multiplex/best.png"]; - } - - // unexpected identifier - return nil; -} - -- (void)multiplexImageNode:(ASMultiplexImageNode *)imageNode didFinishDownloadingImageWithIdentifier:(id)imageIdentifier error:(NSError *)error -{ - _textLabel.text = [NSString stringWithFormat:@"loaded '%@'", imageIdentifier]; - - if ([imageIdentifier isEqualToString:@"best"]) { - _textLabel.text = [_textLabel.text stringByAppendingString:@". tap to reload"]; - _textLabel.userInteractionEnabled = YES; - } -} - - -#pragma mark - -#pragma mark ASImageDownloaderProtocol. - -- (id)downloadImageWithURL:(NSURL *)URL - callbackQueue:(dispatch_queue_t)callbackQueue - downloadProgressBlock:(void (^)(CGFloat progress))downloadProgressBlock - completion:(void (^)(CGImageRef image, NSError *error))completion -{ - // if no callback queue is supplied, run on the main thread - if (callbackQueue == nil) { - callbackQueue = dispatch_get_main_queue(); - } - - // call completion blocks - void (^handler)(NSURLResponse *, NSData *, NSError *) = ^(NSURLResponse *response, NSData *data, NSError *connectionError) { - // add an artificial delay - usleep(1.0 * USEC_PER_SEC); - - // ASMultiplexImageNode callbacks - dispatch_async(callbackQueue, ^{ - if (downloadProgressBlock) { - downloadProgressBlock(1.0f); - } - - if (completion) { - completion([[UIImage imageWithData:data] CGImage], connectionError); - } - }); - }; - - // let NSURLConnection do the heavy lifting - NSURLRequest *request = [NSURLRequest requestWithURL:URL]; - [NSURLConnection sendAsynchronousRequest:request - queue:[[NSOperationQueue alloc] init] - completionHandler:handler]; - - // return nil, don't support cancellation - return nil; -} - -- (void)cancelImageDownloadForIdentifier:(id)downloadIdentifier -{ - // no-op, don't support cancellation -} - @end