mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 22:25:57 +00:00
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:
committed by
Hannah Troisi
parent
c7ea15a5e4
commit
ba2268ac99
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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__);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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).
|
||||
*/
|
||||
|
||||
@@ -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.)
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user