2611 rename fetch data (#2689)

* Replace fetch data with preload terminology
- Deprecate `-fetchData` and `-clearFetchedData` in favor of `-preload` and `-clearPreloadedData`
- Move `-setNeedsPreload`, `-recursivelyPreload` and `-recursivelyClearPreloadedData` to ASDisplayNode+FrameworkPrivate.h
- Update internal implementation, comments and tests

* Folllow up on #2642:
- Remove -preload and -clearPreloadedData in favor of -didEnterPreloadState and -didExitPreloadState.
- -didEnterPreloadState and -didExitPreloadState call the deprecated -fetchData and -clearFetchedData methods if they are overriden.

* Missed one in a test

* Get rid of behavior change for now.

* Revert more behavior changes, fix tests.

* Don't need these anymore.
This commit is contained in:
Garrett Moon
2016-12-01 13:41:22 -08:00
committed by Hannah Troisi
parent c7ea15a5e4
commit ba2268ac99
20 changed files with 151 additions and 167 deletions

View File

@@ -167,10 +167,10 @@
[self.rangeController clearContents];
}
- (void)clearFetchedData
- (void)didExitPreloadState
{
[super clearFetchedData];
[self.rangeController clearFetchedData];
[super didExitPreloadState];
[self.rangeController clearPreloadedData];
}
- (void)interfaceStateDidChange:(ASInterfaceState)newState fromState:(ASInterfaceState)oldState

View File

@@ -1681,18 +1681,6 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
_nextLayoutInvalidationStyle = invalidationStyle;
}
#pragma mark - Memory Management
- (void)clearContents
{
[_rangeController clearContents];
}
- (void)clearFetchedData
{
[_rangeController clearFetchedData];
}
#pragma mark - _ASDisplayView behavior substitutions
// Need these to drive interfaceState so we know when we are visible, if not nested in another range-managing element.
// Because our superclass is a true UIKit class, we cannot also subclass _ASDisplayView.

View File

@@ -115,4 +115,21 @@ ASLayoutElementStyleForwardingDeclaration
*/
@property (nonatomic, assign) BOOL usesImplicitHierarchyManagement ASDISPLAYNODE_DEPRECATED_MSG("Set .automaticallyManagesSubnodes instead.");
/**
* @abstract Indicates that the node should fetch any external data, such as images.
*
* @discussion Subclasses may override this method to be notified when they should begin to preload. Fetching
* should be done asynchronously. The node is also responsible for managing the memory of any data.
* The data may be remote and accessed via the network, but could also be a local database query.
*/
- (void)fetchData ASDISPLAYNODE_REQUIRES_SUPER ASDISPLAYNODE_DEPRECATED_MSG("Use -didEnterPreloadState instead.");
/**
* Provides an opportunity to clear any fetched data (e.g. remote / network or database-queried) on the current node.
*
* @discussion This will not clear data recursively for all subnodes. Either call -recursivelyClearPreloadedData or
* selectively clear fetched data.
*/
- (void)clearFetchedData ASDISPLAYNODE_REQUIRES_SUPER ASDISPLAYNODE_DEPRECATED_MSG("Use -didExitPreloadState instead.");
@end

View File

@@ -323,23 +323,6 @@ NS_ASSUME_NONNULL_BEGIN
*/
@property (nonatomic, readonly, assign, getter=isInHierarchy) BOOL inHierarchy;
/**
* @abstract Indicates that the node should fetch any external data, such as images.
*
* @discussion Subclasses may override this method to be notified when they should begin to fetch data. Fetching
* should be done asynchronously. The node is also responsible for managing the memory of any data.
* The data may be remote and accessed via the network, but could also be a local database query.
*/
- (void)fetchData ASDISPLAYNODE_REQUIRES_SUPER;
/**
* Provides an opportunity to clear any fetched data (e.g. remote / network or database-queried) on the current node.
*
* @discussion This will not clear data recursively for all subnodes. Either call -recursivelyClearFetchedData or
* selectively clear fetched data.
*/
- (void)clearFetchedData ASDISPLAYNODE_REQUIRES_SUPER;
/**
* Provides an opportunity to clear backing store and other memory-intensive intermediates, such as text layout managers
* on the current node.

View File

@@ -478,31 +478,6 @@ extern NSInteger const ASDefaultDrawingPriority;
*/
- (void)recursivelyClearContents;
/**
* @abstract Calls -clearFetchedData on the receiver and its subnode hierarchy.
*
* @discussion Clears any memory-intensive fetched content.
* This method is used to notify the node that it should purge any content that is both expensive to fetch and to
* retain in memory.
*
* @see [ASDisplayNode(Subclassing) clearFetchedData] and [ASDisplayNode(Subclassing) fetchData]
*/
- (void)recursivelyClearFetchedData;
/**
* @abstract Calls -fetchData on the receiver and its subnode hierarchy.
*
* @discussion Fetches content from remote sources for the current node and all subnodes.
*
* @see [ASDisplayNode(Subclassing) fetchData] and [ASDisplayNode(Subclassing) clearFetchedData]
*/
- (void)recursivelyFetchData;
/**
* @abstract Triggers a recursive call to fetchData when the node has an interfaceState of ASInterfaceStatePreload
*/
- (void)setNeedsDataFetch;
/**
* @abstract Toggle displaying a placeholder over the node that covers content until the node and all subnodes are
* displayed.

View File

@@ -184,6 +184,12 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
if (ASDisplayNodeSubclassOverridesSelector(c, @selector(layoutSpecThatFits:))) {
overrides |= ASDisplayNodeMethodOverrideLayoutSpecThatFits;
}
if (ASDisplayNodeSubclassOverridesSelector(c, @selector(fetchData))) {
overrides |= ASDisplayNodeMethodOverrideFetchData;
}
if (ASDisplayNodeSubclassOverridesSelector(c, @selector(clearFetchedData))) {
overrides |= ASDisplayNodeMethodOverrideClearFetchedData;
}
return overrides;
}
@@ -211,7 +217,7 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(layoutThatFits:)), @"Subclass %@ must not override layoutThatFits: method. Instead overwrite calculateLayoutThatFits:.", classString);
ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(layoutThatFits:parentSize:)), @"Subclass %@ must not override layoutThatFits:parentSize method. Instead overwrite calculateLayoutThatFits:.", classString);
ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(recursivelyClearContents)), @"Subclass %@ must not override recursivelyClearContents method.", classString);
ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(recursivelyClearFetchedData)), @"Subclass %@ must not override recursivelyClearFetchedData method.", classString);
ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(recursivelyClearPreloadedData)), @"Subclass %@ must not override recursivelyClearFetchedData method.", classString);
}
// Below we are pre-calculating values per-class and dynamically adding a method (_staticInitialize) to populate these values
@@ -2930,34 +2936,24 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
});
}
- (void)fetchData
{
// subclass override
}
- (void)setNeedsDataFetch
- (void)setNeedsPreload
{
if (self.isInPreloadState) {
[self recursivelyFetchData];
[self recursivelyPreload];
}
}
- (void)recursivelyFetchData
- (void)recursivelyPreload
{
ASDisplayNodePerformBlockOnEveryNode(nil, self, YES, ^(ASDisplayNode * _Nonnull node) {
[node fetchData];
[node didEnterPreloadState];
});
}
- (void)clearFetchedData
{
// subclass override
}
- (void)recursivelyClearFetchedData
- (void)recursivelyClearPreloadedData
{
ASDisplayNodePerformBlockOnEveryNode(nil, self, YES, ^(ASDisplayNode * _Nonnull node) {
[node clearFetchedData];
[node didExitPreloadState];
});
}
@@ -2983,13 +2979,23 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
- (void)didEnterPreloadState
{
[self fetchData];
if (_methodOverrides & ASDisplayNodeMethodOverrideFetchData) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
[self fetchData];
#pragma clang diagnostic pop
}
}
- (void)didExitPreloadState
{
if ([self supportsRangeManagedInterfaceState]) {
if (_methodOverrides & ASDisplayNodeMethodOverrideClearFetchedData) {
if ([self supportsRangeManagedInterfaceState]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
[self clearFetchedData];
#pragma clang diagnostic pop
}
}
}
@@ -3047,7 +3053,7 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
// Trigger asynchronous measurement if it is not already cached or being calculated.
}
// For the FetchData and Display ranges, we don't want to call -clear* if not being managed by a range controller.
// For the Preload and Display ranges, we don't want to call -clear* if not being managed by a range controller.
// Otherwise we get flashing behavior from normal UIKit manipulations like navigation controller push / pop.
// Still, the interfaceState should be updated to the current state of the node; just don't act on the transition.
@@ -3062,7 +3068,7 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
[self didExitPreloadState];
}
}
// Entered or exited contents rendering state.
BOOL nowDisplay = ASInterfaceStateIncludesDisplay(newState);
BOOL wasDisplay = ASInterfaceStateIncludesDisplay(oldState);
@@ -3946,6 +3952,16 @@ ASLayoutElementStyleForwarding
}
}
- (void)fetchData
{
// subclass override
}
- (void)clearFetchedData
{
// subclass override
}
- (void)cancelLayoutTransitionsInProgress
{
[self cancelLayoutTransition];

View File

@@ -72,9 +72,9 @@
[super setLayerBacked:layerBacked];
}
- (void)fetchData
- (void)didEnterPreloadState
{
[super fetchData];
[super didEnterPreloadState];
ASPerformBlockOnMainThread(^{
if (self.isLiveMap) {
[self addLiveMap];
@@ -84,9 +84,9 @@
});
}
- (void)clearFetchedData
- (void)didExitPreloadState
{
[super clearFetchedData];
[super didExitPreloadState];
ASPerformBlockOnMainThread(^{
if (self.isLiveMap) {
[self removeLiveMap];

View File

@@ -216,12 +216,12 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent
[super clearContents]; // This actually clears the contents, so we need to do this first for our displayedImageIdentifier to be meaningful.
[self _setDisplayedImageIdentifier:nil withImage:nil];
// NOTE: We intentionally do not cancel image downloads until `clearFetchedData`.
// NOTE: We intentionally do not cancel image downloads until `clearPreloadedData`.
}
- (void)clearFetchedData
- (void)didExitPreloadState
{
[super clearFetchedData];
[super didExitPreloadState];
[_phImageRequestOperation cancel];
@@ -236,9 +236,9 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent
self.image = nil;
}
- (void)fetchData
- (void)didEnterPreloadState
{
[super fetchData];
[super didEnterPreloadState];
[self _loadImageIdentifiers];
}
@@ -281,7 +281,7 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent
{
[super displayWillStart];
[self fetchData];
[self didEnterPreloadState];
if (_downloaderImplementsSetPriority) {
{
@@ -396,7 +396,7 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent
_imageIdentifiers = [[NSArray alloc] initWithArray:imageIdentifiers copyItems:YES];
}
[self setNeedsDataFetch];
[self setNeedsPreload];
}
- (void)reloadImageIdentifierSources

View File

@@ -145,7 +145,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
});
}
[self setNeedsDataFetch];
[self setNeedsPreload];
}
- (NSURL *)URL
@@ -265,8 +265,8 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
}
}
// TODO: Consider removing this; it predates ASInterfaceState, which now ensures that even non-range-managed nodes get a -fetchData call.
[self fetchData];
// TODO: Consider removing this; it predates ASInterfaceState, which now ensures that even non-range-managed nodes get a -preload call.
[self didEnterPreloadState];
if (self.image == nil && _downloaderFlags.downloaderImplementsSetPriority) {
ASDN::MutexLocker l(__instanceLock__);
@@ -306,9 +306,9 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
[self _updateProgressImageBlockOnDownloaderIfNeeded];
}
- (void)clearFetchedData
- (void)didExitPreloadState
{
[super clearFetchedData];
[super didExitPreloadState];
{
ASDN::MutexLocker l(__instanceLock__);
@@ -321,9 +321,9 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
}
}
- (void)fetchData
- (void)didEnterPreloadState
{
[super fetchData];
[super didEnterPreloadState];
{
ASDN::MutexLocker l(__instanceLock__);

View File

@@ -136,10 +136,10 @@
[self.rangeController clearContents];
}
- (void)clearFetchedData
- (void)didExitPreloadState
{
[super clearFetchedData];
[self.rangeController clearFetchedData];
[super didExitPreloadState];
[self.rangeController clearPreloadedData];
}
- (void)interfaceStateDidChange:(ASInterfaceState)newState fromState:(ASInterfaceState)oldState

View File

@@ -1646,18 +1646,6 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
[super endUpdates];
}
#pragma mark - Memory Management
- (void)clearContents
{
[_rangeController clearContents];
}
- (void)clearFetchedData
{
[_rangeController clearFetchedData];
}
#pragma mark - Helper Methods
// Note: This is called every layout, and so it is very performance sensitive.

View File

@@ -11,6 +11,7 @@
#import <AVFoundation/AVFoundation.h>
#import "ASDisplayNodeInternal.h"
#import "ASDisplayNode+Subclasses.h"
#import "ASDisplayNode+FrameworkPrivate.h"
#import "ASVideoNode.h"
#import "ASEqualityHelpers.h"
#import "ASInternalHelpers.h"
@@ -365,9 +366,9 @@ static NSString * const kRate = @"rate";
}
}
- (void)fetchData
- (void)didEnterPreloadState
{
[super fetchData];
[super didEnterPreloadState];
ASDN::MutexLocker l(__instanceLock__);
AVAsset *asset = self.asset;
@@ -405,9 +406,9 @@ static NSString * const kRate = @"rate";
}
}
- (void)clearFetchedData
- (void)didExitPreloadState
{
[super clearFetchedData];
[super didExitPreloadState];
{
ASDN::MutexLocker l(__instanceLock__);
@@ -505,10 +506,10 @@ static NSString * const kRate = @"rate";
- (void)_setAndFetchAsset:(AVAsset *)asset url:(NSURL *)assetURL
{
[self clearFetchedData];
[self didExitPreloadState];
_asset = asset;
_assetURL = assetURL;
[self setNeedsDataFetch];
[self setNeedsPreload];
}
- (void)setVideoComposition:(AVVideoComposition *)videoComposition
@@ -617,7 +618,7 @@ static NSString * const kRate = @"rate";
}
if (_player == nil) {
[self setNeedsDataFetch];
[self setNeedsPreload];
}
if (_playerNode == nil) {

View File

@@ -55,7 +55,7 @@ typedef void(^ASImageCacherCompletion)(id <ASImageContainerProtocol> _Nullable i
completion:(ASImageCacherCompletion)completion;
/**
@abstract Called during clearFetchedData. Allows the cache to optionally trim items.
@abstract Called during clearPreloadedData. Allows the cache to optionally trim items.
@note Depending on your caches implementation you may *not* wish to respond to this method. It is however useful
if you have a memory and disk cache in which case you'll likely want to clear out the memory cache.
*/

View File

@@ -31,8 +31,8 @@ typedef NS_ENUM(NSUInteger, ASLayoutRangeMode) {
ASLayoutRangeModeFull,
/**
* Visible Only mode is used when a range controller should set its display and fetch data regions to only the size of their bounds.
* This causes all additional backing stores & fetched data to be released, while ensuring a user revisiting the view will
* Visible Only mode is used when a range controller should set its display and preload regions to only the size of their bounds.
* This causes all additional backing stores & preloaded data to be released, while ensuring a user revisiting the view will
* still be able to see the expected content. This mode is automatically set on all ASRangeControllers when the app suspends,
* allowing the operating system to keep the app alive longer and increase the chance it is still warm when the user returns.
*/
@@ -40,7 +40,7 @@ typedef NS_ENUM(NSUInteger, ASLayoutRangeMode) {
/**
* Low Memory mode is used when a range controller should discard ALL graphics buffers, including for the area that would be visible
* the next time the user views it (bounds). The only range it preserves is Fetch Data, which is limited to the bounds, allowing
* the next time the user views it (bounds). The only range it preserves is Preload, which is limited to the bounds, allowing
* the content to be restored relatively quickly by re-decoding images (the compressed images are ~10% the size of the decoded ones,
* and text is a tiny fraction of its rendered size).
*/

View File

@@ -69,7 +69,7 @@ NS_ASSUME_NONNULL_BEGIN
// These methods call the corresponding method on each node, visiting each one that
// the range controller has set a non-default interface state on.
- (void)clearContents;
- (void)clearFetchedData;
- (void)clearPreloadedData;
/**
* An object that describes the layout behavior of the ranged component (table view, collection view, etc.)

View File

@@ -250,7 +250,7 @@ static UIApplicationState __ApplicationState = UIApplicationStateActive;
// Typically the preloadIndexPaths will be the largest, and be a superset of the others, though it may be disjoint.
// Because allIndexPaths is an NSMutableOrderedSet, this adds the non-duplicate items /after/ the existing items.
// This means that during iteration, we will first visit visible, then display, then fetch data nodes.
// This means that during iteration, we will first visit visible, then display, then preload nodes.
[allIndexPaths unionSet:displayIndexPaths];
[allIndexPaths unionSet:preloadIndexPaths];
@@ -292,14 +292,14 @@ static UIApplicationState __ApplicationState = UIApplicationStateActive;
}
} else {
// If selfInterfaceState isn't visible, then visibleIndexPaths represents what /will/ be immediately visible at the
// instant we come onscreen. So, fetch data and display all of those things, but don't waste resources preloading yet.
// instant we come onscreen. So, preload and display all of those things, but don't waste resources preloading yet.
// We handle this as a separate case to minimize set operations for offscreen preloading, including containsObject:.
if ([allCurrentIndexPaths containsObject:indexPath]) {
// DO NOT set Visible: even though these elements are in the visible range / "viewport",
// our overall container object is itself not visible yet. The moment it becomes visible, we will run the condition above
// Set Layout, Fetch Data
// Set Layout, Preload
interfaceState |= ASInterfaceStatePreload;
if (rangeMode != ASLayoutRangeModeLowMemory) {
@@ -501,7 +501,7 @@ static UIApplicationState __ApplicationState = UIApplicationStateActive;
}
}
- (void)clearFetchedData
- (void)clearPreloadedData
{
for (NSArray *section in [_dataSource completedNodes]) {
for (ASDisplayNode *node in section) {

View File

@@ -156,6 +156,31 @@ __unused static NSString * _Nonnull NSStringFromASHierarchyState(ASHierarchyStat
*/
- (void)recursivelyEnsureDisplaySynchronously:(BOOL)synchronously;
/**
* @abstract Calls -didExitPreloadState on the receiver and its subnode hierarchy.
*
* @discussion Clears any memory-intensive preloaded content.
* This method is used to notify the node that it should purge any content that is both expensive to fetch and to
* retain in memory.
*
* @see [ASDisplayNode(Subclassing) didExitPreloadState] and [ASDisplayNode(Subclassing) didEnterPreloadState]
*/
- (void)recursivelyClearPreloadedData;
/**
* @abstract Calls -didEnterPreloadState on the receiver and its subnode hierarchy.
*
* @discussion Fetches content from remote sources for the current node and all subnodes.
*
* @see [ASDisplayNode(Subclassing) didEnterPreloadState] and [ASDisplayNode(Subclassing) didExitPreloadState]
*/
- (void)recursivelyPreload;
/**
* @abstract Triggers a recursive call to -didEnterPreloadState when the node has an interfaceState of ASInterfaceStatePreload
*/
- (void)setNeedsPreload;
/**
* @abstract Allows a node to bypass all ensureDisplay passes. Defaults to NO.
*

View File

@@ -44,7 +44,9 @@ typedef NS_OPTIONS(NSUInteger, ASDisplayNodeMethodOverrides)
ASDisplayNodeMethodOverrideTouchesCancelled = 1 << 1,
ASDisplayNodeMethodOverrideTouchesEnded = 1 << 2,
ASDisplayNodeMethodOverrideTouchesMoved = 1 << 3,
ASDisplayNodeMethodOverrideLayoutSpecThatFits = 1 << 4
ASDisplayNodeMethodOverrideLayoutSpecThatFits = 1 << 4,
ASDisplayNodeMethodOverrideFetchData = 1 << 5,
ASDisplayNodeMethodOverrideClearFetchedData = 1 << 6
};
FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayScheduledNodesNotification;

View File

@@ -89,7 +89,6 @@ for (ASDisplayNode *n in @[ nodes ]) {\
@interface ASTestDisplayNode : ASDisplayNode
@property (nonatomic, copy) void (^willDeallocBlock)(__unsafe_unretained ASTestDisplayNode *node);
@property (nonatomic, copy) CGSize(^calculateSizeBlock)(ASTestDisplayNode *node, CGSize size);
@property (nonatomic) BOOL hasFetchedData;
@property (nonatomic, nullable) UIGestureRecognizer *gestureRecognizer;
@property (nonatomic, nullable) id idGestureRecognizer;
@@ -99,6 +98,7 @@ for (ASDisplayNode *n in @[ nodes ]) {\
@property (nonatomic) BOOL displayRangeStateChangedToYES;
@property (nonatomic) BOOL displayRangeStateChangedToNO;
@property (nonatomic) BOOL hasPreloaded;
@property (nonatomic) BOOL preloadStateChangedToYES;
@property (nonatomic) BOOL preloadStateChangedToNO;
@end
@@ -113,18 +113,6 @@ for (ASDisplayNode *n in @[ nodes ]) {\
return _calculateSizeBlock ? _calculateSizeBlock(self, constrainedSize) : CGSizeZero;
}
- (void)fetchData
{
[super fetchData];
self.hasFetchedData = YES;
}
- (void)clearFetchedData
{
[super clearFetchedData];
self.hasFetchedData = NO;
}
- (void)didEnterDisplayState
{
[super didEnterDisplayState];
@@ -141,6 +129,7 @@ for (ASDisplayNode *n in @[ nodes ]) {\
{
[super didEnterPreloadState];
self.preloadStateChangedToYES = YES;
self.hasPreloaded = YES;
}
- (void)didExitPreloadState
@@ -1738,76 +1727,76 @@ static inline BOOL _CGPointEqualToPointWithEpsilon(CGPoint point1, CGPoint point
}
// Check that nodes who have no cell node (no range controller)
// do get their `fetchData` called, and they do report
// the fetch data interface state.
// do get their `preload` called, and they do report
// the preload interface state.
- (void)testInterfaceStateForNonCellNode
{
ASTestWindow *window = [ASTestWindow new];
ASTestDisplayNode *node = [ASTestDisplayNode new];
XCTAssert(node.interfaceState == ASInterfaceStateNone);
XCTAssert(!node.hasFetchedData);
XCTAssert(!node.hasPreloaded);
[window addSubview:node.view];
XCTAssert(node.hasFetchedData);
XCTAssert(node.hasPreloaded);
XCTAssert(node.interfaceState == ASInterfaceStateInHierarchy);
[node.view removeFromSuperview];
// We don't want to call -clearFetchedData on nodes that aren't being managed by a range controller.
// We don't want to call -didExitPreloadState on nodes that aren't being managed by a range controller.
// Otherwise we get flashing behavior from normal UIKit manipulations like navigation controller push / pop.
// Still, the interfaceState should be None to reflect the current state of the node.
// We just don't proactively clear contents or fetched data for this state transition.
XCTAssert(node.hasFetchedData);
XCTAssert(node.hasPreloaded);
XCTAssert(node.interfaceState == ASInterfaceStateNone);
}
// Check that nodes who have no cell node (no range controller)
// do get their `fetchData` called, and they do report
// the fetch data interface state.
// do get their `preload` called, and they do report
// the preload interface state.
- (void)testInterfaceStateForCellNode
{
ASCellNode *cellNode = [ASCellNode new];
ASTestDisplayNode *node = [ASTestDisplayNode new];
XCTAssert(node.interfaceState == ASInterfaceStateNone);
XCTAssert(!node.hasFetchedData);
XCTAssert(!node.hasPreloaded);
// Simulate range handler updating cell node.
[cellNode addSubnode:node];
[cellNode enterInterfaceState:ASInterfaceStatePreload];
XCTAssert(node.hasFetchedData);
XCTAssert(node.hasPreloaded);
XCTAssert(node.interfaceState == ASInterfaceStatePreload);
// If the node goes into a view it should not adopt the `InHierarchy` state.
ASTestWindow *window = [ASTestWindow new];
[window addSubview:cellNode.view];
XCTAssert(node.hasFetchedData);
XCTAssert(node.hasPreloaded);
XCTAssert(node.interfaceState == ASInterfaceStateInHierarchy);
}
- (void)testSetNeedsDataFetchImmediateState
- (void)testSetNeedsPreloadImmediateState
{
ASCellNode *cellNode = [ASCellNode new];
ASTestDisplayNode *node = [ASTestDisplayNode new];
[cellNode addSubnode:node];
[cellNode enterInterfaceState:ASInterfaceStatePreload];
node.hasFetchedData = NO;
[cellNode setNeedsDataFetch];
XCTAssert(node.hasFetchedData);
node.hasPreloaded = NO;
[cellNode setNeedsPreload];
XCTAssert(node.hasPreloaded);
}
- (void)testFetchDataExitingAndEnteringRange
- (void)testPreloadExitingAndEnteringRange
{
ASCellNode *cellNode = [ASCellNode new];
ASTestDisplayNode *node = [ASTestDisplayNode new];
[cellNode addSubnode:node];
[cellNode setHierarchyState:ASHierarchyStateRangeManaged];
// Simulate enter range, fetch data, exit range
// Simulate enter range, preload, exit range
[cellNode enterInterfaceState:ASInterfaceStatePreload];
[cellNode exitInterfaceState:ASInterfaceStatePreload];
node.hasFetchedData = NO;
node.hasPreloaded = NO;
[cellNode enterInterfaceState:ASInterfaceStatePreload];
XCTAssert(node.hasFetchedData);
XCTAssert(node.hasPreloaded);
}
- (void)testInitWithViewClass
@@ -2070,8 +2059,8 @@ static bool stringContainsPointer(NSString *description, id p) {
XCTAssertTrue((node.interfaceState & ASInterfaceStatePreload) == ASInterfaceStatePreload);
XCTAssertTrue((subnode.interfaceState & ASInterfaceStatePreload) == ASInterfaceStatePreload);
XCTAssertTrue(node.hasFetchedData);
XCTAssertTrue(subnode.hasFetchedData);
XCTAssertTrue(node.hasPreloaded);
XCTAssertTrue(subnode.hasPreloaded);
}
// FIXME

View File

@@ -133,7 +133,7 @@
XCTAssertNil(_videoNode.player);
}
- (void)testPlayerIsCreatedAsynchronouslyInFetchData
- (void)testPlayerIsCreatedAsynchronouslyInPreload
{
AVAsset *asset = _firstAsset;
@@ -151,7 +151,7 @@
XCTAssertNotNil(_videoNode.player);
}
- (void)testPlayerIsCreatedAsynchronouslyInFetchDataWithURL
- (void)testPlayerIsCreatedAsynchronouslyInPreloadWithURL
{
AVAsset *asset = [AVAsset assetWithURL:_url];
@@ -387,7 +387,7 @@
XCTAssertNotEqual(firstImage, _videoNode.image);
}
- (void)testClearingFetchedContentShouldClearAssetData
- (void)testClearingPreloadedContentShouldClearAssetData
{
AVAsset *asset = _firstAsset;
@@ -398,7 +398,7 @@
[[[videoNodeMock expect] andForwardToRealObject] prepareToPlayAsset:assetMock withKeys:_requestedKeys];
_videoNode.asset = assetMock;
[_videoNode fetchData];
[_videoNode didEnterPreloadState];
[_videoNode setVideoPlaceholderImage:[[UIImage alloc] init]];
[videoNodeMock verifyWithDelay:1.0f];
@@ -407,7 +407,7 @@
XCTAssertNotNil(_videoNode.currentItem);
XCTAssertNotNil(_videoNode.image);
[_videoNode clearFetchedData];
[_videoNode didExitPreloadState];
XCTAssertNil(_videoNode.player);
XCTAssertNil(_videoNode.currentItem);
XCTAssertNil(_videoNode.image);