Start downloading images when multiplex node is displayed

fixes #178
This commit is contained in:
Ryan Nystrom 2015-01-07 16:18:48 -08:00
parent bacfcbd24d
commit ae1349eb16
3 changed files with 25 additions and 44 deletions

View File

@ -70,7 +70,6 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent
// Networking.
id _downloadIdentifier;
BOOL _canceledImageDownload;
}
//! @abstract Read-write redeclaration of property declared in ASMultiplexImageNode.h.
@ -79,16 +78,6 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent
//! @abstract The image identifier that's being loaded by _loadNextImageWithCompletion:.
@property (nonatomic, readwrite, copy) id loadingImageIdentifier;
/**
@abstract Indicates whether a change from one array of image identifiers to another should prompt the receiver to update its loaded image.
@param loadedIdentifier The image identifier that's currently loaded, or nil if no identifier is loaded yet.
@param loadingImageIdentifier The image identifier that's currently loading, or nil if no identifier is loading.
@param oldIdentifiers An array of image identifiers that were previously managed, or nil if no identifiers were managed before.
@param newIdentifiers The array of new image identifiers.
@result YES if the receiver should update its loaded image as a consequence of the newly assigned identifiers; NO otherwise.
*/
static inline BOOL _shouldUpdateAfterChangedImageIdentifiers(id loadedIdentifier, id loadingImageIdentifier, NSArray *oldIdentifiers, NSArray *newIdentifiers);
/**
@abstract Returns the next image identifier that should be downloaded.
@discussion This method obeys and reflects the value of `downloadsIntermediateImages`.
@ -180,7 +169,6 @@ static inline BOOL _shouldUpdateAfterChangedImageIdentifiers(id loadedIdentifier
if (_downloadIdentifier) {
[_downloader cancelImageDownloadForIdentifier:_downloadIdentifier];
_downloadIdentifier = nil;
_canceledImageDownload = YES;
}
}
@ -188,10 +176,7 @@ static inline BOOL _shouldUpdateAfterChangedImageIdentifiers(id loadedIdentifier
{
[super displayWillStart];
if(_canceledImageDownload) {
[self _updatedImageIdentifiers];
_canceledImageDownload = NO;
}
[self _loadImageIdentifiers];
}
- (void)displayDidFinish
@ -268,24 +253,16 @@ static inline BOOL _shouldUpdateAfterChangedImageIdentifiers(id loadedIdentifier
OSSpinLockUnlock(&_imageIdentifiersLock);
return;
}
NSArray *oldImageIdentifiers = [[NSArray alloc] initWithArray:_imageIdentifiers];
_imageIdentifiers = [imageIdentifiers copy];
// Kick off image loading and display, if the identifiers have substantively changed.
BOOL shouldUpdateAfterChangedImageIdentifiers = _shouldUpdateAfterChangedImageIdentifiers(self.loadedImageIdentifier, self.loadingImageIdentifier, oldImageIdentifiers, _imageIdentifiers);
OSSpinLockUnlock(&_imageIdentifiersLock);
if (shouldUpdateAfterChangedImageIdentifiers) {
[self _updatedImageIdentifiers];
}
}
- (void)reloadImageIdentifierSources
{
[self _updatedImageIdentifiers];
// setting this to nil makes the node think it has not downloaded any images
_loadedImageIdentifier = nil;
[self _loadImageIdentifiers];
}
#pragma mark -
@ -325,18 +302,10 @@ static inline BOOL _shouldUpdateAfterChangedImageIdentifiers(id loadedIdentifier
_downloadIdentifier = downloadIdentifier;
}
#pragma mark - Image Loading Machinery
static inline BOOL _shouldUpdateAfterChangedImageIdentifiers(id loadedIdentifier, id loadingImageIdentifier, NSArray *oldIdentifiers, NSArray *newIdentifiers)
{
// If we're loading an identifier, we need to update if it isn't permitted to load anymore.
if (loadingImageIdentifier)
return ![newIdentifiers containsObject:loadingImageIdentifier];
// We're not loading, so we need to update unless we've already loaded the best identifier.
return ![[newIdentifiers firstObject] isEqual:loadedIdentifier];
}
- (void)_updatedImageIdentifiers
- (void)_loadImageIdentifiers
{
// Kill any in-flight downloads.
[self _setDownloadIdentifier:nil];

View File

@ -108,6 +108,7 @@ static BOOL ASRunRunLoopUntilBlockIsTrue(BOOL (^block)())
[[[mockDataSource expect] andReturn:testImage] multiplexImageNode:imageNode imageForImageIdentifier:imageIdentifier];
imageNode.imageIdentifiers = @[imageIdentifier];
[imageNode reloadImageIdentifierSources];
[mockDataSource verify];
@ -153,8 +154,9 @@ static BOOL ASRunRunLoopUntilBlockIsTrue(BOOL (^block)())
completionBlock([self _testImage].CGImage);
}] fetchCachedImageWithURL:[OCMArg any] callbackQueue:[OCMArg any] completion:[OCMArg any]];
// Kick off loading.
imageNode.imageIdentifiers = @[imageIdentifier];
// Kick off loading.
[imageNode reloadImageIdentifierSources];
// Verify the data source.
[mockDataSource verify];
@ -189,6 +191,7 @@ static BOOL ASRunRunLoopUntilBlockIsTrue(BOOL (^block)())
}] multiplexImageNode:[OCMArg any] imageForImageIdentifier:[OCMArg any]];
imageNode.imageIdentifiers = @[highResIdentifier];
[imageNode reloadImageIdentifierSources];
// At this point, we should have the high-res identifier loaded and the DS should have been hit once.
XCTAssertEqualObjects(imageNode.loadedImageIdentifier, highResIdentifier, @"High res identifier should be loaded.");
@ -197,10 +200,11 @@ static BOOL ASRunRunLoopUntilBlockIsTrue(BOOL (^block)())
// Add the low res identifier.
NSNumber *lowResIdentifier = @1;
imageNode.imageIdentifiers = @[highResIdentifier, lowResIdentifier];
[imageNode reloadImageIdentifierSources];
// At this point the high-res should still be loaded, and the data source should not have been hit.
// At this point the high-res should still be loaded, and the data source should have been hit again
XCTAssertEqualObjects(imageNode.loadedImageIdentifier, highResIdentifier, @"High res identifier should be loaded.");
XCTAssertTrue(dataSourceHits == 1, @"Unexpected DS hit count");
XCTAssertTrue(dataSourceHits == 2, @"Unexpected DS hit count");
imageNode.delegate = nil;
imageNode.dataSource = nil;
@ -226,6 +230,7 @@ static BOOL ASRunRunLoopUntilBlockIsTrue(BOOL (^block)())
}] multiplexImageNode:[OCMArg any] imageForImageIdentifier:[OCMArg any]];
imageNode.imageIdentifiers = @[lowResIdentifier];
[imageNode reloadImageIdentifierSources];
// At this point, we should have the low-res identifier loaded and the DS should have been hit once.
XCTAssertEqualObjects(imageNode.loadedImageIdentifier, lowResIdentifier, @"Low res identifier should be loaded.");
@ -234,6 +239,7 @@ static BOOL ASRunRunLoopUntilBlockIsTrue(BOOL (^block)())
// Add the low res identifier.
NSNumber *highResIdentifier = @2;
imageNode.imageIdentifiers = @[highResIdentifier, lowResIdentifier];
[imageNode reloadImageIdentifierSources];
// At this point the high-res should be loaded, and the data source should been hit twice.
XCTAssertEqualObjects(imageNode.loadedImageIdentifier, highResIdentifier, @"High res identifier should be loaded.");
@ -282,6 +288,7 @@ static BOOL ASRunRunLoopUntilBlockIsTrue(BOOL (^block)())
}] multiplexImageNode:[OCMArg any] imageForImageIdentifier:[OCMArg any]];
imageNode.imageIdentifiers = imageIdentifiers;
[imageNode reloadImageIdentifierSources];
XCTAssertTrue(loadedImageCount == identifierCount, @"Expected to load the same number of identifiers we supplied");
@ -331,8 +338,9 @@ static BOOL ASRunRunLoopUntilBlockIsTrue(BOOL (^block)())
[[mockDelegate expect] multiplexImageNode:imageNode didUpdateImage:[OCMArg any] withIdentifier:imageIdentifier fromImage:nil withIdentifier:nil];
imageNode.delegate = mockDelegate;
// Kick off loading.
imageNode.imageIdentifiers = @[imageIdentifier];
// Kick off loading.
[imageNode reloadImageIdentifierSources];
// Wait until the image is loaded.
ASRunRunLoopUntilBlockIsTrue(^BOOL{

View File

@ -50,7 +50,7 @@
_textLabel.font = [UIFont fontWithName:@"HelveticaNeue-Light" size:22.0f];
// tap to reload
UITapGestureRecognizer *gr = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(start)];
UITapGestureRecognizer *gr = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(reload:)];
[_textLabel addGestureRecognizer:gr];
@ -92,10 +92,14 @@
_textLabel.text = @"loading…";
_textLabel.userInteractionEnabled = NO;
_imageNode.imageIdentifiers = nil;
_imageNode.imageIdentifiers = @[ @"best", @"medium", @"worst" ]; // go!
}
- (void)reload:(id)sender {
[self start];
[_imageNode reloadImageIdentifierSources];
}
#pragma mark -
#pragma mark ASMultiplexImageNode data source & delegate.