Functioning Preload range

Refactor how we do ranges so they can be arbitrarily managed. Introduce the concept of a preload range.
This commit is contained in:
Ryan Nystrom
2015-02-02 18:23:45 -08:00
parent 9c877c51af
commit 4fa03a01d1
27 changed files with 477 additions and 222 deletions

View File

@@ -138,6 +138,12 @@
05F20AA41A15733C00DCA68A /* ASImageProtocols.h in Headers */ = {isa = PBXBuildFile; fileRef = 05F20AA31A15733C00DCA68A /* ASImageProtocols.h */; settings = {ATTRIBUTES = (Public, ); }; }; 05F20AA41A15733C00DCA68A /* ASImageProtocols.h in Headers */ = {isa = PBXBuildFile; fileRef = 05F20AA31A15733C00DCA68A /* ASImageProtocols.h */; settings = {ATTRIBUTES = (Public, ); }; };
1950C4491A3BB5C1005C8279 /* ASEqualityHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 1950C4481A3BB5C1005C8279 /* ASEqualityHelpers.h */; }; 1950C4491A3BB5C1005C8279 /* ASEqualityHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 1950C4481A3BB5C1005C8279 /* ASEqualityHelpers.h */; };
2911485C1A77147A005D0878 /* ASControlNodeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2911485B1A77147A005D0878 /* ASControlNodeTests.m */; }; 2911485C1A77147A005D0878 /* ASControlNodeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2911485B1A77147A005D0878 /* ASControlNodeTests.m */; };
292C599F1A956527007E5DD6 /* ASLayoutRangeType.h in Headers */ = {isa = PBXBuildFile; fileRef = 292C59991A956527007E5DD6 /* ASLayoutRangeType.h */; settings = {ATTRIBUTES = (Public, ); }; };
292C59A01A956527007E5DD6 /* ASPreloadRangeDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 292C599A1A956527007E5DD6 /* ASPreloadRangeDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; };
292C59A11A956527007E5DD6 /* ASPreloadRangeDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 292C599B1A956527007E5DD6 /* ASPreloadRangeDelegate.mm */; };
292C59A21A956527007E5DD6 /* ASRangeDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 292C599C1A956527007E5DD6 /* ASRangeDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; };
292C59A31A956527007E5DD6 /* ASRenderRangeDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 292C599D1A956527007E5DD6 /* ASRenderRangeDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; };
292C59A41A956527007E5DD6 /* ASRenderRangeDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 292C599E1A956527007E5DD6 /* ASRenderRangeDelegate.mm */; };
3C9C128519E616EF00E942A0 /* ASTableViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3C9C128419E616EF00E942A0 /* ASTableViewTests.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 3C9C128519E616EF00E942A0 /* ASTableViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3C9C128419E616EF00E942A0 /* ASTableViewTests.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
464052201A3F83C40061C0BA /* ASDataController.h in Headers */ = {isa = PBXBuildFile; fileRef = 464052191A3F83C40061C0BA /* ASDataController.h */; settings = {ATTRIBUTES = (Public, ); }; }; 464052201A3F83C40061C0BA /* ASDataController.h in Headers */ = {isa = PBXBuildFile; fileRef = 464052191A3F83C40061C0BA /* ASDataController.h */; settings = {ATTRIBUTES = (Public, ); }; };
464052211A3F83C40061C0BA /* ASDataController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4640521A1A3F83C40061C0BA /* ASDataController.mm */; }; 464052211A3F83C40061C0BA /* ASDataController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4640521A1A3F83C40061C0BA /* ASDataController.mm */; };
@@ -284,6 +290,12 @@
05F20AA31A15733C00DCA68A /* ASImageProtocols.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASImageProtocols.h; sourceTree = "<group>"; }; 05F20AA31A15733C00DCA68A /* ASImageProtocols.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASImageProtocols.h; sourceTree = "<group>"; };
1950C4481A3BB5C1005C8279 /* ASEqualityHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASEqualityHelpers.h; sourceTree = "<group>"; }; 1950C4481A3BB5C1005C8279 /* ASEqualityHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASEqualityHelpers.h; sourceTree = "<group>"; };
2911485B1A77147A005D0878 /* ASControlNodeTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASControlNodeTests.m; sourceTree = "<group>"; }; 2911485B1A77147A005D0878 /* ASControlNodeTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASControlNodeTests.m; sourceTree = "<group>"; };
292C59991A956527007E5DD6 /* ASLayoutRangeType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASLayoutRangeType.h; sourceTree = "<group>"; };
292C599A1A956527007E5DD6 /* ASPreloadRangeDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASPreloadRangeDelegate.h; sourceTree = "<group>"; };
292C599B1A956527007E5DD6 /* ASPreloadRangeDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASPreloadRangeDelegate.mm; sourceTree = "<group>"; };
292C599C1A956527007E5DD6 /* ASRangeDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASRangeDelegate.h; sourceTree = "<group>"; };
292C599D1A956527007E5DD6 /* ASRenderRangeDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASRenderRangeDelegate.h; sourceTree = "<group>"; };
292C599E1A956527007E5DD6 /* ASRenderRangeDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASRenderRangeDelegate.mm; sourceTree = "<group>"; };
3C9C128419E616EF00E942A0 /* ASTableViewTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASTableViewTests.m; sourceTree = "<group>"; }; 3C9C128419E616EF00E942A0 /* ASTableViewTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASTableViewTests.m; sourceTree = "<group>"; };
464052191A3F83C40061C0BA /* ASDataController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASDataController.h; sourceTree = "<group>"; }; 464052191A3F83C40061C0BA /* ASDataController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASDataController.h; sourceTree = "<group>"; };
4640521A1A3F83C40061C0BA /* ASDataController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASDataController.mm; sourceTree = "<group>"; }; 4640521A1A3F83C40061C0BA /* ASDataController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASDataController.mm; sourceTree = "<group>"; };
@@ -463,12 +475,21 @@
058D09E7195D050800B7D73C /* ASHighlightOverlayLayer.mm */, 058D09E7195D050800B7D73C /* ASHighlightOverlayLayer.mm */,
05F20AA31A15733C00DCA68A /* ASImageProtocols.h */, 05F20AA31A15733C00DCA68A /* ASImageProtocols.h */,
4640521D1A3F83C40061C0BA /* ASLayoutController.h */, 4640521D1A3F83C40061C0BA /* ASLayoutController.h */,
292C59991A956527007E5DD6 /* ASLayoutRangeType.h */,
4640521E1A3F83C40061C0BA /* ASMultidimensionalArrayUtils.h */, 4640521E1A3F83C40061C0BA /* ASMultidimensionalArrayUtils.h */,
4640521F1A3F83C40061C0BA /* ASMultidimensionalArrayUtils.mm */, 4640521F1A3F83C40061C0BA /* ASMultidimensionalArrayUtils.mm */,
058D09E8195D050800B7D73C /* ASMutableAttributedStringBuilder.h */, 058D09E8195D050800B7D73C /* ASMutableAttributedStringBuilder.h */,
058D09E9195D050800B7D73C /* ASMutableAttributedStringBuilder.m */, 058D09E9195D050800B7D73C /* ASMutableAttributedStringBuilder.m */,
055F1A3619ABD413004DAFF1 /* ASRangeController.h */, 055F1A3619ABD413004DAFF1 /* ASRangeController.h */,
055F1A3719ABD413004DAFF1 /* ASRangeController.mm */, 055F1A3719ABD413004DAFF1 /* ASRangeController.mm */,
292C599A1A956527007E5DD6 /* ASPreloadRangeDelegate.h */,
292C599B1A956527007E5DD6 /* ASPreloadRangeDelegate.mm */,
055F1A3619ABD413004DAFF1 /* ASRangeController.h */,
055F1A3719ABD413004DAFF1 /* ASRangeController.mm */,
292C599C1A956527007E5DD6 /* ASRangeDelegate.h */,
292C599D1A956527007E5DD6 /* ASRenderRangeDelegate.h */,
292C599E1A956527007E5DD6 /* ASRenderRangeDelegate.mm */,
058D09EA195D050800B7D73C /* ASTextNodeCoreTextAdditions.h */, 058D09EA195D050800B7D73C /* ASTextNodeCoreTextAdditions.h */,
058D09EB195D050800B7D73C /* ASTextNodeCoreTextAdditions.m */, 058D09EB195D050800B7D73C /* ASTextNodeCoreTextAdditions.m */,
058D09EC195D050800B7D73C /* ASTextNodeRenderer.h */, 058D09EC195D050800B7D73C /* ASTextNodeRenderer.h */,
@@ -574,6 +595,7 @@
058D0A51195D05CB00B7D73C /* ASTextNode.h in Headers */, 058D0A51195D05CB00B7D73C /* ASTextNode.h in Headers */,
058D0A52195D05CB00B7D73C /* ASTextNode.mm in Headers */, 058D0A52195D05CB00B7D73C /* ASTextNode.mm in Headers */,
055F1A3819ABD413004DAFF1 /* ASRangeController.h in Headers */, 055F1A3819ABD413004DAFF1 /* ASRangeController.h in Headers */,
292C59A31A956527007E5DD6 /* ASRenderRangeDelegate.h in Headers */,
055F1A3419ABD3E3004DAFF1 /* ASTableView.h in Headers */, 055F1A3419ABD3E3004DAFF1 /* ASTableView.h in Headers */,
0574D5E219C110940097DC25 /* ASTableViewProtocols.h in Headers */, 0574D5E219C110940097DC25 /* ASTableViewProtocols.h in Headers */,
055F1A3C19ABD43F004DAFF1 /* ASCellNode.h in Headers */, 055F1A3C19ABD43F004DAFF1 /* ASCellNode.h in Headers */,
@@ -594,6 +616,7 @@
058D0A61195D05DC00B7D73C /* ASTextNodeTextKitHelpers.h in Headers */, 058D0A61195D05DC00B7D73C /* ASTextNodeTextKitHelpers.h in Headers */,
058D0A62195D05DC00B7D73C /* ASTextNodeTextKitHelpers.mm in Headers */, 058D0A62195D05DC00B7D73C /* ASTextNodeTextKitHelpers.mm in Headers */,
058D0A63195D05DC00B7D73C /* ASTextNodeTypes.h in Headers */, 058D0A63195D05DC00B7D73C /* ASTextNodeTypes.h in Headers */,
292C599F1A956527007E5DD6 /* ASLayoutRangeType.h in Headers */,
464052251A3F83C40061C0BA /* ASMultidimensionalArrayUtils.h in Headers */, 464052251A3F83C40061C0BA /* ASMultidimensionalArrayUtils.h in Headers */,
058D0A64195D05DC00B7D73C /* ASTextNodeWordKerner.h in Headers */, 058D0A64195D05DC00B7D73C /* ASTextNodeWordKerner.h in Headers */,
058D0A65195D05DC00B7D73C /* ASTextNodeWordKerner.m in Headers */, 058D0A65195D05DC00B7D73C /* ASTextNodeWordKerner.m in Headers */,
@@ -615,6 +638,7 @@
058D0A83195D060300B7D73C /* ASBaseDefines.h in Headers */, 058D0A83195D060300B7D73C /* ASBaseDefines.h in Headers */,
058D0A84195D060300B7D73C /* ASDisplayNodeExtraIvars.h in Headers */, 058D0A84195D060300B7D73C /* ASDisplayNodeExtraIvars.h in Headers */,
AC3C4A511A1139C100143C57 /* ASCollectionView.h in Headers */, AC3C4A511A1139C100143C57 /* ASCollectionView.h in Headers */,
292C59A01A956527007E5DD6 /* ASPreloadRangeDelegate.h in Headers */,
055B9FA81A1C154B00035D6D /* ASNetworkImageNode.h in Headers */, 055B9FA81A1C154B00035D6D /* ASNetworkImageNode.h in Headers */,
054963491A1EA066000F8E56 /* ASBasicImageDownloader.h in Headers */, 054963491A1EA066000F8E56 /* ASBasicImageDownloader.h in Headers */,
AC3C4A541A113EEC00143C57 /* ASCollectionViewProtocols.h in Headers */, AC3C4A541A113EEC00143C57 /* ASCollectionViewProtocols.h in Headers */,
@@ -634,6 +658,7 @@
058D0A7B195D05F900B7D73C /* ASDisplayNodeInternal.h in Headers */, 058D0A7B195D05F900B7D73C /* ASDisplayNodeInternal.h in Headers */,
058D0A7C195D05F900B7D73C /* ASImageNode+CGExtras.h in Headers */, 058D0A7C195D05F900B7D73C /* ASImageNode+CGExtras.h in Headers */,
058D0A7D195D05F900B7D73C /* ASImageNode+CGExtras.m in Headers */, 058D0A7D195D05F900B7D73C /* ASImageNode+CGExtras.m in Headers */,
292C59A21A956527007E5DD6 /* ASRangeDelegate.h in Headers */,
058D0A7F195D05F900B7D73C /* ASSentinel.h in Headers */, 058D0A7F195D05F900B7D73C /* ASSentinel.h in Headers */,
058D0A80195D05F900B7D73C /* ASSentinel.m in Headers */, 058D0A80195D05F900B7D73C /* ASSentinel.m in Headers */,
058D0A81195D05F900B7D73C /* ASThread.h in Headers */, 058D0A81195D05F900B7D73C /* ASThread.h in Headers */,
@@ -770,8 +795,10 @@
464052261A3F83C40061C0BA /* ASMultidimensionalArrayUtils.mm in Sources */, 464052261A3F83C40061C0BA /* ASMultidimensionalArrayUtils.mm in Sources */,
055B9FA91A1C154B00035D6D /* ASNetworkImageNode.mm in Sources */, 055B9FA91A1C154B00035D6D /* ASNetworkImageNode.mm in Sources */,
058D0A1D195D050800B7D73C /* ASTextNodeRenderer.mm in Sources */, 058D0A1D195D050800B7D73C /* ASTextNodeRenderer.mm in Sources */,
292C59A41A956527007E5DD6 /* ASRenderRangeDelegate.mm in Sources */,
058D0A2A195D050800B7D73C /* ASDisplayNode+UIViewBridge.mm in Sources */, 058D0A2A195D050800B7D73C /* ASDisplayNode+UIViewBridge.mm in Sources */,
AC3C4A521A1139C100143C57 /* ASCollectionView.mm in Sources */, AC3C4A521A1139C100143C57 /* ASCollectionView.mm in Sources */,
292C59A11A956527007E5DD6 /* ASPreloadRangeDelegate.mm in Sources */,
058D0A20195D050800B7D73C /* ASTextNodeWordKerner.m in Sources */, 058D0A20195D050800B7D73C /* ASTextNodeWordKerner.m in Sources */,
058D0A1A195D050800B7D73C /* ASHighlightOverlayLayer.mm in Sources */, 058D0A1A195D050800B7D73C /* ASHighlightOverlayLayer.mm in Sources */,
464052231A3F83C40061C0BA /* ASFlowLayoutController.mm in Sources */, 464052231A3F83C40061C0BA /* ASFlowLayoutController.mm in Sources */,

View File

@@ -39,7 +39,7 @@
* Defaults to the render range having one sceenful both leading and trailing and the preload range having two * Defaults to the render range having one sceenful both leading and trailing and the preload range having two
* screenfuls in both directions. * screenfuls in both directions.
*/ */
- (ASRangeTuningParameters)tuningParametersForRange:(ASLayoutRange)range; - (ASRangeTuningParameters)tuningParametersForRangeType:(ASLayoutRangeType)rangeType;
/** /**
* Set the tuning parameters for a range. * Set the tuning parameters for a range.
@@ -47,7 +47,7 @@
* @param tuningParameters The tuning parameters to store for a range. * @param tuningParameters The tuning parameters to store for a range.
* @param range The range to set the tuning parameters for. * @param range The range to set the tuning parameters for.
*/ */
- (void)setTuningParameters:(ASRangeTuningParameters)tuningParameters forRange:(ASLayoutRange)range; - (void)setTuningParameters:(ASRangeTuningParameters)tuningParameters forRangeType:(ASLayoutRangeType)rangeType;
/** /**
* Initializer. * Initializer.

View File

@@ -199,24 +199,24 @@ static BOOL _isInterceptedSelector(SEL sel)
super.delegate = (id<UICollectionViewDelegate>)_proxyDelegate; super.delegate = (id<UICollectionViewDelegate>)_proxyDelegate;
} }
- (void)setTuningParameters:(ASRangeTuningParameters)tuningParameters forRange:(ASLayoutRange)range - (void)setTuningParameters:(ASRangeTuningParameters)tuningParameters forRangeType:(ASLayoutRangeType)rangeType
{ {
[_layoutController setTuningParameters:tuningParameters forRange:range]; [_layoutController setTuningParameters:tuningParameters forRangeType:rangeType];
} }
- (ASRangeTuningParameters)tuningParametersForRange:(ASLayoutRange)range - (ASRangeTuningParameters)tuningParametersForRangeType:(ASLayoutRangeType)rangeType
{ {
return [_layoutController tuningParametersForRange:range]; return [_layoutController tuningParametersForRangeType:rangeType];
} }
- (ASRangeTuningParameters)rangeTuningParameters - (ASRangeTuningParameters)rangeTuningParameters
{ {
return [self tuningParametersForRange:ASLayoutRangeRender]; return [self tuningParametersForRangeType:ASLayoutRangeTypeRender];
} }
- (void)setRangeTuningParameters:(ASRangeTuningParameters)tuningParameters - (void)setRangeTuningParameters:(ASRangeTuningParameters)tuningParameters
{ {
[self setTuningParameters:tuningParameters forRange:ASLayoutRangeRender]; [self setTuningParameters:tuningParameters forRangeType:ASLayoutRangeTypeRender];
} }
- (CGSize)calculatedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath - (CGSize)calculatedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath

View File

@@ -185,6 +185,14 @@
*/ */
- (void)displayDidFinish ASDISPLAYNODE_REQUIRES_SUPER; - (void)displayDidFinish ASDISPLAYNODE_REQUIRES_SUPER;
/**
* @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.
*/
- (void)fetchRemoteData ASDISPLAYNODE_REQUIRES_SUPER;
/** /**
* @abstract Indicates that the receiver is about to display its subnodes. This method is not called if there are no * @abstract Indicates that the receiver is about to display its subnodes. This method is not called if there are no
* subnodes present. * subnodes present.
@@ -312,13 +320,20 @@
- (void)didExitHierarchy ASDISPLAYNODE_REQUIRES_SUPER; - (void)didExitHierarchy ASDISPLAYNODE_REQUIRES_SUPER;
/** /**
* Provides an opportunity to clear backing store and other memory-intensive intermediates, such as text layout managers * Provides an opportunity to clear backing store and other memory-intensive intermediates, such as text layout managers.
* or downloaded content that can be written to a disk cache.
* *
* @discussion Called by -recursivelyReclaimMemory. Base class implements self.contents = nil, clearing any backing * @discussion Called by -recursivelyClearRendering. Base class implements self.contents = nil, clearing any backing
* store, for asynchronous regeneration when needed. * store, for asynchronous regeneration when needed.
*/ */
- (void)reclaimMemory ASDISPLAYNODE_REQUIRES_SUPER; - (void)clearRendering ASDISPLAYNODE_REQUIRES_SUPER;
/**
* Provides an opportunity to clear any remote data for only the current node.
*
* @discussion This will not clear data recursively for all subnodes. Either call -recursivelyClearRemoteData or
* selectively clear remote data.
*/
- (void)clearRemoteData ASDISPLAYNODE_REQUIRES_SUPER;
/** @name Placeholders */ /** @name Placeholders */

View File

@@ -312,7 +312,7 @@ typedef CALayer *(^ASDisplayNodeLayerBlock)();
- (void)recursivelySetDisplaySuspended:(BOOL)flag; - (void)recursivelySetDisplaySuspended:(BOOL)flag;
/** /**
* @abstract Calls -reclaimMemory on the receiver and its subnode hierarchy. * @abstract Calls -clearRendering on the receiver and its subnode hierarchy.
* *
* @discussion Clears backing stores and other memory-intensive intermediates. * @discussion Clears backing stores and other memory-intensive intermediates.
* If the node is removed from a visible hierarchy and then re-added, it will automatically trigger a new asynchronous display, * If the node is removed from a visible hierarchy and then re-added, it will automatically trigger a new asynchronous display,
@@ -322,7 +322,18 @@ typedef CALayer *(^ASDisplayNodeLayerBlock)();
* @see displaySuspended and setNeedsDisplay * @see displaySuspended and setNeedsDisplay
*/ */
- (void)recursivelyReclaimMemory; - (void)recursivelyClearRendering;
/**
* @abstract Calls -clearRemoteData 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 fetchRemoteData
*/
- (void)recursivelyClearRemoteData;
/** /**
* @abstract Toggle displaying a placeholder over the node that covers content until the node and all subnodes are * @abstract Toggle displaying a placeholder over the node that covers content until the node and all subnodes are
@@ -539,5 +550,9 @@ typedef CALayer *(^ASDisplayNodeLayerBlock)();
@end @end
@interface ASDisplayNode (Deprecated) @interface ASDisplayNode (Deprecated)
- (void)reclaimMemory ASDISPLAYNODE_DEPRECATED;
- (void)recursivelyReclaimMemory ASDISPLAYNODE_DEPRECATED;
@property (nonatomic, assign) BOOL placeholderFadesOut ASDISPLAYNODE_DEPRECATED; @property (nonatomic, assign) BOOL placeholderFadesOut ASDISPLAYNODE_DEPRECATED;
@end @end

View File

@@ -90,7 +90,7 @@ void ASDisplayNodePerformBlockOnMainThread(void (^block)())
// Subclasses should never override these // Subclasses should never override these
ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(calculatedSize)), @"Subclass %@ must not override calculatedSize method", NSStringFromClass(self)); ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(calculatedSize)), @"Subclass %@ must not override calculatedSize method", NSStringFromClass(self));
ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(measure:)), @"Subclass %@ must not override measure method", NSStringFromClass(self)); ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(measure:)), @"Subclass %@ must not override measure method", NSStringFromClass(self));
ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(recursivelyReclaimMemory)), @"Subclass %@ must not override recursivelyReclaimMemory method", NSStringFromClass(self)); ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(recursivelyClearRendering)), @"Subclass %@ must not override recursivelyClearRendering method", NSStringFromClass(self));
} }
+ (BOOL)layerBackedNodesEnabled + (BOOL)layerBackedNodesEnabled
@@ -1328,18 +1328,36 @@ static NSInteger incrementIfFound(NSInteger i) {
[self __exitedHierarchy]; [self __exitedHierarchy];
} }
- (void)reclaimMemory - (void)clearRendering
{ {
self.layer.contents = nil; self.layer.contents = nil;
_placeholderLayer.contents = nil; _placeholderLayer.contents = nil;
} }
- (void)recursivelyReclaimMemory - (void)recursivelyClearRendering
{ {
for (ASDisplayNode *subnode in self.subnodes) { for (ASDisplayNode *subnode in self.subnodes) {
[subnode recursivelyReclaimMemory]; [subnode recursivelyClearRendering];
} }
[self reclaimMemory]; [self clearRendering];
}
- (void)fetchRemoteData
{
// subclass override
}
- (void)clearRemoteData
{
// subclass override
}
- (void)recursivelyClearRemoteData
{
for (ASDisplayNode *subnode in self.subnodes) {
[subnode recursivelyClearRemoteData];
}
[self clearRemoteData];
} }
- (void)layout - (void)layout
@@ -1460,6 +1478,7 @@ static NSInteger incrementIfFound(NSInteger i) {
} }
} }
#pragma mark - Pending View State #pragma mark - Pending View State
- (_ASPendingState *)pendingViewState - (_ASPendingState *)pendingViewState
{ {
@@ -1786,4 +1805,14 @@ static const char *ASDisplayNodeAssociatedNodeKey = "ASAssociatedNode";
return self.placeholderFadeDuration > 0.0; return self.placeholderFadeDuration > 0.0;
} }
- (void)reclaimMemory
{
[self clearRendering];
}
- (void)recursivelyReclaimMemory
{
[self recursivelyClearRendering];
}
@end @end

View File

@@ -162,9 +162,9 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent
} }
#pragma mark - ASDisplayNode Overrides #pragma mark - ASDisplayNode Overrides
- (void)reclaimMemory - (void)clearRendering
{ {
[super reclaimMemory]; // This actually clears the contents, so we need to do this first for our displayedImageIdentifier to be meaningful. [super clearRendering]; // This actually clears the contents, so we need to do this first for our displayedImageIdentifier to be meaningful.
[self _setDisplayedImageIdentifier:nil withImage:nil]; [self _setDisplayedImageIdentifier:nil withImage:nil];
if (_downloadIdentifier) { if (_downloadIdentifier) {
@@ -177,6 +177,13 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent
{ {
[super displayWillStart]; [super displayWillStart];
[self fetchRemoteData];
}
- (void)fetchRemoteData
{
[super fetchRemoteData];
[self _loadImageIdentifiers]; [self _loadImageIdentifiers];
} }

View File

@@ -123,9 +123,16 @@
return _delegate; return _delegate;
} }
- (void)reclaimMemory - (void)displayWillStart
{ {
[super reclaimMemory]; [super displayWillStart];
[self fetchRemoteData];
}
- (void)clearRemoteData
{
[super clearRemoteData];
{ {
ASDN::MutexLocker l(_lock); ASDN::MutexLocker l(_lock);
@@ -136,10 +143,10 @@
} }
} }
- (void)displayWillStart - (void)fetchRemoteData
{ {
[super displayWillStart]; [super fetchRemoteData];
{ {
ASDN::MutexLocker l(_lock); ASDN::MutexLocker l(_lock);
[self _lazilyLoadImageIfNecessary]; [self _lazilyLoadImageIfNecessary];

View File

@@ -32,22 +32,22 @@
/** /**
* Tuning parameters for a range. * Tuning parameters for a range.
* *
* @param range The range to get the tuning parameters for. * @param rangeType The range to get the tuning parameters for.
* *
* @returns A tuning parameter value for the given range. * @returns A tuning parameter value for the given range.
* *
* Defaults to the render range having one sceenful both leading and trailing and the preload range having two * Defaults to the render range having one sceenful both leading and trailing and the preload range having two
* screenfuls in both directions. * screenfuls in both directions.
*/ */
- (ASRangeTuningParameters)tuningParametersForRange:(ASLayoutRange)range; - (ASRangeTuningParameters)tuningParametersForRangeType:(ASLayoutRangeType)rangeType;
/** /**
* Set the tuning parameters for a range. * Set the tuning parameters for a range.
* *
* @param tuningParameters The tuning parameters to store for a range. * @param tuningParameters The tuning parameters to store for a range.
* @param range The range to set the tuning parameters for. * @param rangeType The range to set the tuning parameters for.
*/ */
- (void)setTuningParameters:(ASRangeTuningParameters)tuningParameters forRange:(ASLayoutRange)range; - (void)setTuningParameters:(ASRangeTuningParameters)tuningParameters forRangeType:(ASLayoutRangeType)rangeType;
/** /**
* initializer. * initializer.

View File

@@ -201,24 +201,24 @@ static BOOL _isInterceptedSelector(SEL sel)
[_dataController reloadDataWithAnimationOption:UITableViewRowAnimationNone]; [_dataController reloadDataWithAnimationOption:UITableViewRowAnimationNone];
} }
- (void)setTuningParameters:(ASRangeTuningParameters)tuningParameters forRange:(ASLayoutRange)range - (void)setTuningParameters:(ASRangeTuningParameters)tuningParameters forRangeType:(ASLayoutRangeType)rangeType
{ {
[_layoutController setTuningParameters:tuningParameters forRange:range]; [_layoutController setTuningParameters:tuningParameters forRangeType:rangeType];
} }
- (ASRangeTuningParameters)tuningParametersForRange:(ASLayoutRange)range - (ASRangeTuningParameters)tuningParametersForRangeType:(ASLayoutRangeType)rangeType
{ {
return [_layoutController tuningParametersForRange:range]; return [_layoutController tuningParametersForRangeType:rangeType];
} }
- (ASRangeTuningParameters)rangeTuningParameters - (ASRangeTuningParameters)rangeTuningParameters
{ {
return [self tuningParametersForRange:ASLayoutRangeRender]; return [self tuningParametersForRangeType:ASLayoutRangeTypeRender];
} }
- (void)setRangeTuningParameters:(ASRangeTuningParameters)tuningParameters - (void)setRangeTuningParameters:(ASRangeTuningParameters)tuningParameters
{ {
[self setTuningParameters:tuningParameters forRange:ASLayoutRangeRender]; [self setTuningParameters:tuningParameters forRangeType:ASLayoutRangeTypeRender];
} }
- (ASCellNode *)nodeForRowAtIndexPath:(NSIndexPath *)indexPath - (ASCellNode *)nodeForRowAtIndexPath:(NSIndexPath *)indexPath

View File

@@ -212,12 +212,12 @@ ASDISPLAYNODE_INLINE CGFloat ceilPixelValue(CGFloat f)
[self _invalidateRenderer]; [self _invalidateRenderer];
} }
- (void)reclaimMemory - (void)clearRendering
{ {
// We discard the backing store and renderer to prevent the very large // We discard the backing store and renderer to prevent the very large
// memory overhead of maintaining these for all text nodes. They can be // memory overhead of maintaining these for all text nodes. They can be
// regenerated when layout is necessary. // regenerated when layout is necessary.
[super reclaimMemory]; // ASDisplayNode will set layer.contents = nil [super clearRendering]; // ASDisplayNode will set layer.contents = nil
[self _invalidateRenderer]; [self _invalidateRenderer];
} }

View File

@@ -1,4 +1,10 @@
// Copyright 2004-present Facebook. All Rights Reserved. /* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#import <AsyncDisplayKit/ASDealloc2MainObject.h> #import <AsyncDisplayKit/ASDealloc2MainObject.h>

View File

@@ -1,4 +1,10 @@
// Copyright 2004-present Facebook. All Rights Reserved. /* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import "ASDataController.h" #import "ASDataController.h"

View File

@@ -1,4 +1,10 @@
// Copyright 2004-present Facebook. All Rights Reserved. /* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import <AsyncDisplayKit/ASLayoutController.h> #import <AsyncDisplayKit/ASLayoutController.h>
#import <AsyncDisplayKit/ASBaseDefines.h> #import <AsyncDisplayKit/ASBaseDefines.h>
@@ -14,9 +20,9 @@ typedef NS_ENUM(NSUInteger, ASFlowLayoutDirection) {
*/ */
@interface ASFlowLayoutController : NSObject <ASLayoutController> @interface ASFlowLayoutController : NSObject <ASLayoutController>
- (void)setTuningParameters:(ASRangeTuningParameters)tuningParameters forRange:(ASLayoutRange)range; - (void)setTuningParameters:(ASRangeTuningParameters)tuningParameters forRangeType:(ASLayoutRangeType)rangeType;
- (ASRangeTuningParameters)tuningParametersForRange:(ASLayoutRange)range; - (ASRangeTuningParameters)tuningParametersForRangeType:(ASLayoutRangeType)rangeType;
@property (nonatomic, readonly, assign) ASFlowLayoutDirection layoutDirection; @property (nonatomic, readonly, assign) ASFlowLayoutDirection layoutDirection;

View File

@@ -1,4 +1,10 @@
// Copyright 2004-present Facebook. All Rights Reserved. /* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import "ASFlowLayoutController.h" #import "ASFlowLayoutController.h"
@@ -33,17 +39,14 @@ static const CGFloat kASFlowLayoutControllerRefreshingThreshold = 0.3;
_layoutDirection = layoutDirection; _layoutDirection = layoutDirection;
_tuningParameterMap = { _tuningParameterMap = std::vector<ASRangeTuningParameters>(2);
{ _tuningParameterMap[ASLayoutRangeTypePreload] = {
// Render .leadingBufferScreenfuls = 2,
.leadingBufferScreenfuls = 1, .trailingBufferScreenfuls = 1
.trailingBufferScreenfuls = 1 };
}, _tuningParameterMap[ASLayoutRangeTypeRender] = {
{ .leadingBufferScreenfuls = 3,
// Preload .trailingBufferScreenfuls = 2
.leadingBufferScreenfuls = 2,
.trailingBufferScreenfuls = 2
}
}; };
return self; return self;
@@ -51,28 +54,28 @@ static const CGFloat kASFlowLayoutControllerRefreshingThreshold = 0.3;
#pragma mark - Tuning Parameters #pragma mark - Tuning Parameters
- (ASRangeTuningParameters)tuningParametersForRange:(ASLayoutRange)range - (ASRangeTuningParameters)tuningParametersForRangeType:(ASLayoutRangeType)rangeType
{ {
ASDisplayNodeAssert(range < _tuningParameterMap.size(), @"Requesting a range that is OOB for the configured tuning parameters"); ASDisplayNodeAssert(rangeType < _tuningParameterMap.size(), @"Requesting a range that is OOB for the configured tuning parameters");
return _tuningParameterMap[range]; return _tuningParameterMap[rangeType];
} }
- (void)setTuningParameters:(ASRangeTuningParameters)tuningParameters forRange:(ASLayoutRange)range - (void)setTuningParameters:(ASRangeTuningParameters)tuningParameters forRangeType:(ASLayoutRangeType)rangeType
{ {
ASDisplayNodeAssert(range < _tuningParameterMap.size(), @"Requesting a range that is OOB for the configured tuning parameters"); ASDisplayNodeAssert(rangeType < _tuningParameterMap.size(), @"Requesting a range that is OOB for the configured tuning parameters");
_tuningParameterMap[range] = tuningParameters; _tuningParameterMap[rangeType] = tuningParameters;
} }
// Support for the deprecated tuningParameters property // Support for the deprecated tuningParameters property
- (ASRangeTuningParameters)tuningParameters - (ASRangeTuningParameters)tuningParameters
{ {
return [self tuningParametersForRange:ASLayoutRangeRender]; return [self tuningParametersForRangeType:ASLayoutRangeTypeRender];
} }
// Support for the deprecated tuningParameters property // Support for the deprecated tuningParameters property
- (void)setTuningParameters:(ASRangeTuningParameters)tuningParameters - (void)setTuningParameters:(ASRangeTuningParameters)tuningParameters
{ {
[self setTuningParameters:tuningParameters forRange:ASLayoutRangeRender]; [self setTuningParameters:tuningParameters forRangeType:ASLayoutRangeTypeRender];
} }
#pragma mark - Editing #pragma mark - Editing
@@ -120,7 +123,7 @@ static const CGFloat kASFlowLayoutControllerRefreshingThreshold = 0.3;
#pragma mark - Visible Indices #pragma mark - Visible Indices
- (BOOL)shouldUpdateForVisibleIndexPaths:(NSArray *)indexPaths viewportSize:(CGSize)viewportSize range:(ASLayoutRange)range - (BOOL)shouldUpdateForVisibleIndexPaths:(NSArray *)indexPaths viewportSize:(CGSize)viewportSize rangeType:(ASLayoutRangeType)rangeType
{ {
if (!indexPaths.count) { if (!indexPaths.count) {
return NO; return NO;
@@ -128,9 +131,9 @@ static const CGFloat kASFlowLayoutControllerRefreshingThreshold = 0.3;
std::pair<int, int> rangeStartPos, rangeEndPos; std::pair<int, int> rangeStartPos, rangeEndPos;
if (range < _rangeStartPos.size() && range < _rangeEndPos.size()) { if (rangeType < _rangeStartPos.size() && rangeType < _rangeEndPos.size()) {
rangeStartPos = _rangeStartPos[range]; rangeStartPos = _rangeStartPos[rangeType];
rangeEndPos = _rangeEndPos[range]; rangeEndPos = _rangeEndPos[rangeType];
} }
std::pair<int, int> startPos, endPos; std::pair<int, int> startPos, endPos;
@@ -147,7 +150,7 @@ static const CGFloat kASFlowLayoutControllerRefreshingThreshold = 0.3;
- (BOOL)shouldUpdateForVisibleIndexPath:(NSArray *)indexPaths - (BOOL)shouldUpdateForVisibleIndexPath:(NSArray *)indexPaths
viewportSize:(CGSize)viewportSize viewportSize:(CGSize)viewportSize
{ {
return [self shouldUpdateForVisibleIndexPaths:indexPaths viewportSize:viewportSize range:ASLayoutRangeRender]; return [self shouldUpdateForVisibleIndexPaths:indexPaths viewportSize:viewportSize rangeType:ASLayoutRangeTypeRender];
} }
- (void)setVisibleNodeIndexPaths:(NSArray *)indexPaths - (void)setVisibleNodeIndexPaths:(NSArray *)indexPaths
@@ -159,7 +162,7 @@ static const CGFloat kASFlowLayoutControllerRefreshingThreshold = 0.3;
* IndexPath array for the element in the working range. * IndexPath array for the element in the working range.
*/ */
- (NSSet *)indexPathsForScrolling:(enum ASScrollDirection)scrollDirection viewportSize:(CGSize)viewportSize range:(ASLayoutRange)range - (NSSet *)indexPathsForScrolling:(enum ASScrollDirection)scrollDirection viewportSize:(CGSize)viewportSize rangeType:(ASLayoutRangeType)rangeType
{ {
CGFloat viewportScreenMetric; CGFloat viewportScreenMetric;
ASScrollDirection leadingDirection; ASScrollDirection leadingDirection;
@@ -176,12 +179,12 @@ static const CGFloat kASFlowLayoutControllerRefreshingThreshold = 0.3;
leadingDirection = ASScrollDirectionUp; leadingDirection = ASScrollDirectionUp;
} }
ASRangeTuningParameters tuningParameters = [self tuningParametersForRange:range]; ASRangeTuningParameters tuningParameters = [self tuningParametersForRangeType:rangeType];
CGFloat backScreens = scrollDirection == leadingDirection ? tuningParameters.leadingBufferScreenfuls : tuningParameters.trailingBufferScreenfuls; CGFloat backScreens = scrollDirection == leadingDirection ? tuningParameters.leadingBufferScreenfuls : tuningParameters.trailingBufferScreenfuls;
CGFloat frontScreens = scrollDirection == leadingDirection ? tuningParameters.trailingBufferScreenfuls : tuningParameters.leadingBufferScreenfuls; CGFloat frontScreens = scrollDirection == leadingDirection ? tuningParameters.trailingBufferScreenfuls : tuningParameters.leadingBufferScreenfuls;
std::pair<int, int> startIter = ASFindIndexForRange(_nodeSizes, _visibleRangeStartPos, - backScreens * viewportSize.height, _layoutDirection); std::pair<int, int> startIter = ASFindIndexForRange(_nodeSizes, _visibleRangeStartPos, - backScreens * viewportScreenMetric, _layoutDirection);
std::pair<int, int> endIter = ASFindIndexForRange(_nodeSizes, _visibleRangeEndPos, frontScreens * viewportSize.height, _layoutDirection); std::pair<int, int> endIter = ASFindIndexForRange(_nodeSizes, _visibleRangeEndPos, frontScreens * viewportScreenMetric, _layoutDirection);
NSMutableSet *indexPathSet = [[NSMutableSet alloc] init]; NSMutableSet *indexPathSet = [[NSMutableSet alloc] init];
@@ -203,7 +206,7 @@ static const CGFloat kASFlowLayoutControllerRefreshingThreshold = 0.3;
- (NSSet *)indexPathsForScrolling:(enum ASScrollDirection)scrollDirection - (NSSet *)indexPathsForScrolling:(enum ASScrollDirection)scrollDirection
viewportSize:(CGSize)viewportSize viewportSize:(CGSize)viewportSize
{ {
return [self indexPathsForScrolling:scrollDirection viewportSize:viewportSize range:ASLayoutRangeRender]; return [self indexPathsForScrolling:scrollDirection viewportSize:viewportSize rangeType:ASLayoutRangeTypeRender];
} }
#pragma mark - Utility #pragma mark - Utility

View File

@@ -1,8 +1,15 @@
// Copyright 2004-present Facebook. All Rights Reserved. /* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#import <AsyncDisplayKit/ASBaseDefines.h> #import <AsyncDisplayKit/ASBaseDefines.h>
#import <AsyncDisplayKit/ASLayoutRangeType.h>
typedef struct { typedef struct {
CGFloat leadingBufferScreenfuls; CGFloat leadingBufferScreenfuls;
@@ -17,11 +24,6 @@ typedef NS_ENUM(NSInteger, ASScrollDirection) {
ASScrollDirectionDown, ASScrollDirectionDown,
}; };
typedef NS_ENUM(NSInteger, ASLayoutRange) {
ASLayoutRangeRender,
ASLayoutRangePreload
};
@protocol ASLayoutController <NSObject> @protocol ASLayoutController <NSObject>
/** /**
@@ -29,7 +31,7 @@ typedef NS_ENUM(NSInteger, ASLayoutRange) {
* *
* Defaults to a trailing buffer of one screenful and a leading buffer of two screenfuls. * Defaults to a trailing buffer of one screenful and a leading buffer of two screenfuls.
*/ */
- (ASRangeTuningParameters)tuningParametersForRange:(ASLayoutRange)range; - (ASRangeTuningParameters)tuningParametersForRangeType:(ASLayoutRangeType)rangeType;
- (void)insertNodesAtIndexPaths:(NSArray *)indexPaths withSizes:(NSArray *)nodeSizes; - (void)insertNodesAtIndexPaths:(NSArray *)indexPaths withSizes:(NSArray *)nodeSizes;
@@ -41,9 +43,9 @@ typedef NS_ENUM(NSInteger, ASLayoutRange) {
- (void)setVisibleNodeIndexPaths:(NSArray *)indexPaths; - (void)setVisibleNodeIndexPaths:(NSArray *)indexPaths;
- (BOOL)shouldUpdateForVisibleIndexPaths:(NSArray *)indexPaths viewportSize:(CGSize)viewportSize range:(ASLayoutRange)range; - (BOOL)shouldUpdateForVisibleIndexPaths:(NSArray *)indexPaths viewportSize:(CGSize)viewportSize rangeType:(ASLayoutRangeType)rangeType;
- (NSSet *)indexPathsForScrolling:(enum ASScrollDirection)scrollDirection viewportSize:(CGSize)viewportSize range:(ASLayoutRange)range; - (NSSet *)indexPathsForScrolling:(enum ASScrollDirection)scrollDirection viewportSize:(CGSize)viewportSize rangeType:(ASLayoutRangeType)rangeType;
@property (nonatomic, assign) ASRangeTuningParameters tuningParameters ASDISPLAYNODE_DEPRECATED; @property (nonatomic, assign) ASRangeTuningParameters tuningParameters ASDISPLAYNODE_DEPRECATED;

View File

@@ -0,0 +1,15 @@
/* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import <Foundation/Foundation.h>
typedef NS_ENUM(NSInteger, ASLayoutRangeType) {
ASLayoutRangeTypeRender,
ASLayoutRangeTypePreload,
ASLayoutRangeTypeCount
};

View File

@@ -1,4 +1,10 @@
// Copyright 2004-present Facebook. All Rights Reserved. /* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>

View File

@@ -1,4 +1,10 @@
// Copyright 2004-present Facebook. All Rights Reserved. /* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import "ASAssert.h" #import "ASAssert.h"
#import "ASMultidimensionalArrayUtils.h" #import "ASMultidimensionalArrayUtils.h"

View File

@@ -0,0 +1,15 @@
/* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import <Foundation/Foundation.h>
#import <AsyncDisplayKit/ASRangeDelegate.h>
@interface ASPreloadRangeDelegate : NSObject <ASRangeDelegate>
@end

View File

@@ -0,0 +1,26 @@
/* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import "ASPreloadRangeDelegate.h"
#import "ASDisplayNode.h"
#import "ASDisplayNode+Subclasses.h"
@implementation ASPreloadRangeDelegate
- (void)node:(ASDisplayNode *)node enteredRangeType:(ASLayoutRangeType)rangeType
{
[node fetchRemoteData];
}
- (void)node:(ASDisplayNode *)node exitedRangeType:(ASLayoutRangeType)rangeType
{
[node clearRemoteData];
}
@end

View File

@@ -20,7 +20,7 @@
* Working range controller. * Working range controller.
* *
* Used internally by ASTableView and potentially by a future ASCollectionView. Observes the visible range, maintains * Used internally by ASTableView and potentially by a future ASCollectionView. Observes the visible range, maintains
* a working range, and is responsible for handling AsyncDisplayKit machinery (sizing cell nodes, enqueueing and * a working range, and is responsible for handling AsyncDisplayKit machinery (sizing cell nodes,x enqueueing and
* cancelling their asynchronous layout and display, and so on). * cancelling their asynchronous layout and display, and so on).
*/ */
@interface ASRangeController : ASDealloc2MainObject <ASDataControllerDelegate> @interface ASRangeController : ASDealloc2MainObject <ASDataControllerDelegate>

View File

@@ -11,62 +11,16 @@
#import "ASAssert.h" #import "ASAssert.h"
#import "ASDisplayNodeExtras.h" #import "ASDisplayNodeExtras.h"
#import "ASDisplayNodeInternal.h" #import "ASDisplayNodeInternal.h"
#import "ASLayoutController.h"
#import "ASMultiDimensionalArrayUtils.h" #import "ASMultiDimensionalArrayUtils.h"
#import "ASRenderRangeDelegate.h"
@interface ASDisplayNode (ASRangeController) #import "ASPreloadRangeDelegate.h"
- (void)display;
- (void)recursivelyDisplay;
@end
@implementation ASDisplayNode (ASRangeController)
- (void)display
{
if (![self __shouldLoadViewOrLayer]) {
return;
}
ASDisplayNodeAssertMainThread();
ASDisplayNodeAssert(self.nodeLoaded, @"backing store must be loaded before calling -display");
CALayer *layer = self.layer;
// rendering a backing store requires a node be laid out
[layer setNeedsLayout];
[layer layoutIfNeeded];
if (layer.contents) {
return;
}
[layer setNeedsDisplay];
[layer displayIfNeeded];
}
- (void)recursivelyDisplay
{
if (![self __shouldLoadViewOrLayer]) {
return;
}
for (ASDisplayNode *node in self.subnodes) {
[node recursivelyDisplay];
}
[self display];
}
@end
@interface ASRangeController () { @interface ASRangeController () {
NSSet *_workingRangeIndexPaths; BOOL _rangeIsValid;
NSSet *_workingRangeNodes;
BOOL _workingRangeIsValid; // keys should be ASLayoutRangeTypes and values NSSets containing NSIndexPaths
NSMutableDictionary *_rangeTypeIndexPaths;
NSDictionary *_rangeTypeDelegates;
BOOL _queuedRangeUpdate; BOOL _queuedRangeUpdate;
ASScrollDirection _scrollDirection; ASScrollDirection _scrollDirection;
@@ -79,63 +33,32 @@
- (instancetype)init { - (instancetype)init {
if (self = [super init]) { if (self = [super init]) {
_workingRangeIndexPaths = [NSSet set]; _rangeIsValid = YES;
_workingRangeIsValid = YES; _rangeTypeIndexPaths = [[NSMutableDictionary alloc] init];
_rangeTypeDelegates = @{
@(ASLayoutRangeTypeRender): [[ASRenderRangeDelegate alloc] init],
@(ASLayoutRangeTypePreload): [[ASPreloadRangeDelegate alloc] init],
};
} }
return self; return self;
} }
#pragma mark - View manipulation.
- (void)discardNode:(ASCellNode *)node #pragma mark - View manipulation
{
ASDisplayNodeAssertMainThread();
ASDisplayNodeAssert(node, @"invalid argument");
if ([_workingRangeNodes containsObject:node]) {
// move the node's view to the working range area, so its rendering persists
[self addNodeToWorkingRange:node];
} else {
// this node isn't in the working range, remove it from the view hierarchy
[self removeNodeFromWorkingRange:node];
}
}
- (void)removeNodeFromWorkingRange:(ASCellNode *)node
{
ASDisplayNodeAssertMainThread();
ASDisplayNodeAssert(node, @"invalid argument");
[node recursivelySetDisplaySuspended:YES];
[node.view removeFromSuperview];
// since this class usually manages large or infinite data sets, the working range
// directly bounds memory usage by requiring redrawing any content that falls outside the range.
[node recursivelyReclaimMemory];
}
- (void)addNodeToWorkingRange:(ASCellNode *)node
{
ASDisplayNodeAssertMainThread();
ASDisplayNodeAssert(node, @"invalid argument");
// if node is in the working range it should not actively be in view
[node.view removeFromSuperview];
[node recursivelyDisplay];
}
- (void)moveNode:(ASCellNode *)node toView:(UIView *)view - (void)moveNode:(ASCellNode *)node toView:(UIView *)view
{ {
ASDisplayNodeAssertMainThread(); ASDisplayNodeAssertMainThread();
ASDisplayNodeAssert(node && view, @"invalid argument, did you mean -removeNodeFromWorkingRange:?"); ASDisplayNodeAssert(node, @"Cannot move a nil node to a view");
ASDisplayNodeAssert(view, @"Cannot move a node to a non-existent view");
[view addSubview:node.view]; [view addSubview:node.view];
} }
#pragma mark -
#pragma mark API. #pragma mark - API
- (void)visibleNodeIndexPathsDidChangeWithScrollDirection:(ASScrollDirection)scrollDirection - (void)visibleNodeIndexPathsDidChangeWithScrollDirection:(ASScrollDirection)scrollDirection
{ {
@@ -159,42 +82,64 @@
return; return;
} }
NSArray *indexPaths = [_delegate rangeControllerVisibleNodeIndexPaths:self]; NSArray *visibleNodePaths = [_delegate rangeControllerVisibleNodeIndexPaths:self];
NSSet *visibleNodePathsSet = [NSSet setWithArray:visibleNodePaths];
CGSize viewportSize = [_delegate rangeControllerViewportSize:self]; CGSize viewportSize = [_delegate rangeControllerViewportSize:self];
if ([_layoutController shouldUpdateForVisibleIndexPaths:indexPaths viewportSize:viewportSize range:ASLayoutRangeRender]) { // the layout controller needs to know what the current visible indices are to calculate range offsets
[_layoutController setVisibleNodeIndexPaths:indexPaths]; [_layoutController setVisibleNodeIndexPaths:visibleNodePaths];
NSSet *workingRangeIndexPaths = [_layoutController indexPathsForScrolling:_scrollDirection viewportSize:viewportSize range:ASLayoutRangeRender];
NSSet *visibleRangeIndexPaths = [NSSet setWithArray:indexPaths];
NSMutableSet *removedIndexPaths = _workingRangeIsValid ? [_workingRangeIndexPaths mutableCopy] : [NSMutableSet set]; for (NSInteger i = 0; i < ASLayoutRangeTypeCount; i++) {
[removedIndexPaths minusSet:workingRangeIndexPaths]; ASLayoutRangeType rangeType = (ASLayoutRangeType)i;
[removedIndexPaths minusSet:visibleRangeIndexPaths]; id rangeKey = @(rangeType);
if (removedIndexPaths.count) {
NSArray *removedNodes = [_delegate rangeController:self nodesAtIndexPaths:[removedIndexPaths allObjects]]; // this delegate decide what happens when a node is added or removed from a range
[removedNodes enumerateObjectsUsingBlock:^(ASCellNode *node, NSUInteger idx, BOOL *stop) { id<ASRangeDelegate> rangeDelegate = _rangeTypeDelegates[rangeKey];
[self removeNodeFromWorkingRange:node];
}]; if ([_layoutController shouldUpdateForVisibleIndexPaths:visibleNodePaths viewportSize:viewportSize rangeType:rangeType]) {
NSSet *indexPaths = [_layoutController indexPathsForScrolling:_scrollDirection viewportSize:viewportSize rangeType:rangeType];
// Notify to remove indexpaths that are leftover that are not visible or included in the _layoutController calculated paths
NSMutableSet *removedIndexPaths = _rangeIsValid ? [[_rangeTypeIndexPaths objectForKey:rangeKey] mutableCopy] : [NSMutableSet set];
[removedIndexPaths minusSet:indexPaths];
[removedIndexPaths minusSet:visibleNodePathsSet];
if (removedIndexPaths.count) {
NSArray *removedNodes = [_delegate rangeController:self nodesAtIndexPaths:[removedIndexPaths allObjects]];
[removedNodes enumerateObjectsUsingBlock:^(ASCellNode *node, NSUInteger idx, BOOL *stop) {
[rangeDelegate node:node exitedRangeType:rangeType];
}];
}
// Notify to add indexpaths that are not currently in _rangeTypeIndexPaths
NSMutableSet *addedIndexPaths = [indexPaths mutableCopy];
[addedIndexPaths minusSet:[_rangeTypeIndexPaths objectForKey:rangeKey]];
// The preload range (for example) should include nodes that are visible
if ([self shouldRemoveVisibleNodesFromRangeType:rangeType]) {
[addedIndexPaths minusSet:visibleNodePathsSet];
}
if (addedIndexPaths.count) {
NSArray *addedNodes = [_delegate rangeController:self nodesAtIndexPaths:[addedIndexPaths allObjects]];
[addedNodes enumerateObjectsUsingBlock:^(ASCellNode *node, NSUInteger idx, BOOL *stop) {
[rangeDelegate node:node enteredRangeType:rangeType];
}];
}
// set the range indexpaths so that we can remove/add on the next update pass
[_rangeTypeIndexPaths setObject:indexPaths forKey:rangeKey];
} }
NSMutableSet *addedIndexPaths = [workingRangeIndexPaths mutableCopy];
[addedIndexPaths minusSet:_workingRangeIndexPaths];
[addedIndexPaths minusSet:visibleRangeIndexPaths];
if (addedIndexPaths.count) {
NSArray *addedNodes = [_delegate rangeController:self nodesAtIndexPaths:[addedIndexPaths allObjects]];
[addedNodes enumerateObjectsUsingBlock:^(ASCellNode *node, NSUInteger idx, BOOL *stop) {
[self addNodeToWorkingRange:node];
}];
}
_workingRangeIndexPaths = workingRangeIndexPaths;
_workingRangeNodes = [NSSet setWithArray:[_delegate rangeController:self nodesAtIndexPaths:[workingRangeIndexPaths allObjects]]];
_workingRangeIsValid = YES;
} }
_rangeIsValid = YES;
_queuedRangeUpdate = NO; _queuedRangeUpdate = NO;
} }
- (BOOL)shouldRemoveVisibleNodesFromRangeType:(ASLayoutRangeType)rangeType
{
return rangeType != ASLayoutRangeTypePreload;
}
- (void)configureContentView:(UIView *)contentView forCellNode:(ASCellNode *)cellNode - (void)configureContentView:(UIView *)contentView forCellNode:(ASCellNode *)cellNode
{ {
[cellNode recursivelySetDisplaySuspended:NO]; [cellNode recursivelySetDisplaySuspended:NO];
@@ -204,21 +149,15 @@
return; return;
} }
// clean the content view
for (UIView *view in contentView.subviews) { for (UIView *view in contentView.subviews) {
ASDisplayNode *node = view.asyncdisplaykit_node; [view removeFromSuperview];
if (node) {
// plunk this node back into the working range, if appropriate
ASDisplayNodeAssert([node isKindOfClass:[ASCellNode class]], @"invalid node");
[self discardNode:(ASCellNode *)node];
} else {
// if it's not a node, it's something random UITableView added to the hierarchy. kill it.
[view removeFromSuperview];
}
} }
[self moveNode:cellNode toView:contentView]; [self moveNode:cellNode toView:contentView];
} }
#pragma mark - ASDataControllerDelegete #pragma mark - ASDataControllerDelegete
- (void)dataControllerBeginUpdates:(ASDataController *)dataController { - (void)dataControllerBeginUpdates:(ASDataController *)dataController {
@@ -252,7 +191,7 @@
ASDisplayNodePerformBlockOnMainThread(^{ ASDisplayNodePerformBlockOnMainThread(^{
[_layoutController insertNodesAtIndexPaths:indexPaths withSizes:nodeSizes]; [_layoutController insertNodesAtIndexPaths:indexPaths withSizes:nodeSizes];
[_delegate rangeController:self didInsertNodesAtIndexPaths:indexPaths withAnimationOption:animationOption]; [_delegate rangeController:self didInsertNodesAtIndexPaths:indexPaths withAnimationOption:animationOption];
_workingRangeIsValid = NO; _rangeIsValid = NO;
}); });
} }
@@ -268,7 +207,7 @@
ASDisplayNodePerformBlockOnMainThread(^{ ASDisplayNodePerformBlockOnMainThread(^{
[_layoutController deleteNodesAtIndexPaths:indexPaths]; [_layoutController deleteNodesAtIndexPaths:indexPaths];
[_delegate rangeController:self didDeleteNodesAtIndexPaths:indexPaths withAnimationOption:animationOption]; [_delegate rangeController:self didDeleteNodesAtIndexPaths:indexPaths withAnimationOption:animationOption];
_workingRangeIsValid = NO; _rangeIsValid = NO;
}); });
} }
@@ -296,7 +235,7 @@
ASDisplayNodePerformBlockOnMainThread(^{ ASDisplayNodePerformBlockOnMainThread(^{
[_layoutController insertSections:sectionNodeSizes atIndexSet:indexSet]; [_layoutController insertSections:sectionNodeSizes atIndexSet:indexSet];
[_delegate rangeController:self didInsertSectionsAtIndexSet:indexSet withAnimationOption:animationOption]; [_delegate rangeController:self didInsertSectionsAtIndexSet:indexSet withAnimationOption:animationOption];
_workingRangeIsValid = NO; _rangeIsValid = NO;
}); });
} }
@@ -312,7 +251,7 @@
ASDisplayNodePerformBlockOnMainThread(^{ ASDisplayNodePerformBlockOnMainThread(^{
[_layoutController deleteSectionsAtIndexSet:indexSet]; [_layoutController deleteSectionsAtIndexSet:indexSet];
[_delegate rangeController:self didDeleteSectionsAtIndexSet:indexSet withAnimationOption:animationOption]; [_delegate rangeController:self didDeleteSectionsAtIndexSet:indexSet withAnimationOption:animationOption];
_workingRangeIsValid = NO; _rangeIsValid = NO;
}); });
} }

View File

@@ -0,0 +1,22 @@
/* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import <Foundation/Foundation.h>
#import <AsyncDisplayKit/ASLayoutRangeType.h>
@class ASDisplayNode;
@protocol ASRangeDelegate <NSObject>
@required
- (void)node:(ASDisplayNode *)node enteredRangeType:(ASLayoutRangeType)rangeType;
- (void)node:(ASDisplayNode *)node exitedRangeType:(ASLayoutRangeType)rangeType;
@end

View File

@@ -0,0 +1,15 @@
/* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import <Foundation/Foundation.h>
#import <AsyncDisplayKit/ASRangeDelegate.h>
@interface ASRenderRangeDelegate : NSObject
@end

View File

@@ -0,0 +1,88 @@
/* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import "ASRenderRangeDelegate.h"
#import "ASDisplayNode.h"
#import "ASDisplayNode+Subclasses.h"
#import "ASDisplayNodeInternal.h"
@interface ASDisplayNode (ASRenderRangeDelegate)
- (void)display;
- (void)recursivelyDisplay;
@end
@implementation ASDisplayNode (ASRenderRangeDelegate)
- (void)display
{
if (![self __shouldLoadViewOrLayer]) {
return;
}
ASDisplayNodeAssertMainThread();
ASDisplayNodeAssert(self.nodeLoaded, @"backing store must be loaded before calling -display");
CALayer *layer = self.layer;
// rendering a backing store requires a node be laid out
[layer setNeedsLayout];
[layer layoutIfNeeded];
if (layer.contents) {
return;
}
[layer setNeedsDisplay];
[layer displayIfNeeded];
}
- (void)recursivelyDisplay
{
if (![self __shouldLoadViewOrLayer]) {
return;
}
for (ASDisplayNode *node in self.subnodes) {
[node recursivelyDisplay];
}
[self display];
}
@end
@implementation ASRenderRangeDelegate
- (void)node:(ASDisplayNode *)node enteredRangeType:(ASLayoutRangeType)rangeType
{
ASDisplayNodeAssertMainThread();
ASDisplayNodeAssert(node, @"invalid argument");
// if node is in the working range it should not actively be in view
[node.view removeFromSuperview];
[node recursivelyDisplay];
}
- (void)node:(ASDisplayNode *)node exitedRangeType:(ASLayoutRangeType)rangeType
{
ASDisplayNodeAssertMainThread();
ASDisplayNodeAssert(node, @"invalid argument");
[node recursivelySetDisplaySuspended:YES];
[node.view removeFromSuperview];
// since this class usually manages large or infinite data sets, the working range
// directly bounds memory usage by requiring redrawing any content that falls outside the range.
[node recursivelyClearRendering];
}
@end

View File

@@ -17,7 +17,7 @@
#import "BlurbNode.h" #import "BlurbNode.h"
#import "KittenNode.h" #import "KittenNode.h"
static const NSInteger kLitterSize = 20; static const NSInteger kLitterSize = 200;
@interface ViewController () <ASTableViewDataSource, ASTableViewDelegate> @interface ViewController () <ASTableViewDataSource, ASTableViewDelegate>