Merge pull request #1201 from maicki/ASRangeControllerCleanup

[ASRangeController] Remove deprecated range controller implementation that is no longer used.
This commit is contained in:
appleguy 2016-02-09 12:23:44 -08:00
commit cae47e23e1
26 changed files with 284 additions and 1056 deletions

View File

@ -186,10 +186,6 @@
257754C21BEE458E00737CA5 /* ASTextKitCoreTextAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 257754BB1BEE458E00737CA5 /* ASTextKitCoreTextAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; };
257754C31BEE458E00737CA5 /* ASTextNodeTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 257754BC1BEE458E00737CA5 /* ASTextNodeTypes.h */; settings = {ATTRIBUTES = (Public, ); }; };
257754C41BEE458E00737CA5 /* ASTextNodeWordKerner.m in Sources */ = {isa = PBXBuildFile; fileRef = 257754BD1BEE458E00737CA5 /* ASTextNodeWordKerner.m */; };
258FF4271C0D152600A83844 /* ASRangeHandlerVisible.h in Headers */ = {isa = PBXBuildFile; fileRef = 258FF4251C0D152600A83844 /* ASRangeHandlerVisible.h */; };
258FF4281C0D152600A83844 /* ASRangeHandlerVisible.mm in Sources */ = {isa = PBXBuildFile; fileRef = 258FF4261C0D152600A83844 /* ASRangeHandlerVisible.mm */; };
25A977EF1C0D2A5500406B62 /* ASRangeHandlerVisible.mm in Sources */ = {isa = PBXBuildFile; fileRef = 258FF4261C0D152600A83844 /* ASRangeHandlerVisible.mm */; };
25BAA16F1C0D18D2002747C7 /* ASRangeHandlerVisible.h in Headers */ = {isa = PBXBuildFile; fileRef = 258FF4251C0D152600A83844 /* ASRangeHandlerVisible.h */; };
25E327561C16819500A2170C /* ASPagerNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 25E327541C16819500A2170C /* ASPagerNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
25E327571C16819500A2170C /* ASPagerNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 25E327541C16819500A2170C /* ASPagerNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
25E327581C16819500A2170C /* ASPagerNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 25E327551C16819500A2170C /* ASPagerNode.m */; };
@ -199,11 +195,6 @@
2911485C1A77147A005D0878 /* ASControlNodeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2911485B1A77147A005D0878 /* ASControlNodeTests.m */; };
291B63FB1AA53A7A000A71B3 /* ASScrollDirection.h in Headers */ = {isa = PBXBuildFile; fileRef = 296A0A311A951715005ACEAA /* ASScrollDirection.h */; settings = {ATTRIBUTES = (Public, ); }; };
292C599F1A956527007E5DD6 /* ASLayoutRangeType.h in Headers */ = {isa = PBXBuildFile; fileRef = 292C59991A956527007E5DD6 /* ASLayoutRangeType.h */; settings = {ATTRIBUTES = (Public, ); }; };
292C59A01A956527007E5DD6 /* ASRangeHandlerPreload.h in Headers */ = {isa = PBXBuildFile; fileRef = 292C599A1A956527007E5DD6 /* ASRangeHandlerPreload.h */; settings = {ATTRIBUTES = (Public, ); }; };
292C59A11A956527007E5DD6 /* ASRangeHandlerPreload.mm in Sources */ = {isa = PBXBuildFile; fileRef = 292C599B1A956527007E5DD6 /* ASRangeHandlerPreload.mm */; };
292C59A21A956527007E5DD6 /* ASRangeHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 292C599C1A956527007E5DD6 /* ASRangeHandler.h */; settings = {ATTRIBUTES = (Public, ); }; };
292C59A31A956527007E5DD6 /* ASRangeHandlerRender.h in Headers */ = {isa = PBXBuildFile; fileRef = 292C599D1A956527007E5DD6 /* ASRangeHandlerRender.h */; settings = {ATTRIBUTES = (Public, ); }; };
292C59A41A956527007E5DD6 /* ASRangeHandlerRender.mm in Sources */ = {isa = PBXBuildFile; fileRef = 292C599E1A956527007E5DD6 /* ASRangeHandlerRender.mm */; };
2967F9E21AB0A5190072E4AB /* ASBasicImageDownloaderInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 2967F9E11AB0A4CF0072E4AB /* ASBasicImageDownloaderInternal.h */; };
296A0A351A951ABF005ACEAA /* ASBatchFetchingTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 296A0A341A951ABF005ACEAA /* ASBatchFetchingTests.m */; };
299DA1A91A828D2900162D41 /* ASBatchContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 299DA1A71A828D2900162D41 /* ASBatchContext.h */; settings = {ATTRIBUTES = (Public, ); }; };
@ -424,11 +415,6 @@
B35062251B010EFD0018CF92 /* ASMutableAttributedStringBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = 058D09E9195D050800B7D73C /* ASMutableAttributedStringBuilder.m */; };
B35062261B010EFD0018CF92 /* ASRangeController.h in Headers */ = {isa = PBXBuildFile; fileRef = 055F1A3619ABD413004DAFF1 /* ASRangeController.h */; settings = {ATTRIBUTES = (Public, ); }; };
B35062271B010EFD0018CF92 /* ASRangeController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 055F1A3719ABD413004DAFF1 /* ASRangeController.mm */; };
B35062281B010EFD0018CF92 /* ASRangeHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 292C599C1A956527007E5DD6 /* ASRangeHandler.h */; settings = {ATTRIBUTES = (Public, ); }; };
B35062291B010EFD0018CF92 /* ASRangeHandlerPreload.h in Headers */ = {isa = PBXBuildFile; fileRef = 292C599A1A956527007E5DD6 /* ASRangeHandlerPreload.h */; settings = {ATTRIBUTES = (Public, ); }; };
B350622A1B010EFD0018CF92 /* ASRangeHandlerPreload.mm in Sources */ = {isa = PBXBuildFile; fileRef = 292C599B1A956527007E5DD6 /* ASRangeHandlerPreload.mm */; };
B350622B1B010EFD0018CF92 /* ASRangeHandlerRender.h in Headers */ = {isa = PBXBuildFile; fileRef = 292C599D1A956527007E5DD6 /* ASRangeHandlerRender.h */; settings = {ATTRIBUTES = (Public, ); }; };
B350622C1B010EFD0018CF92 /* ASRangeHandlerRender.mm in Sources */ = {isa = PBXBuildFile; fileRef = 292C599E1A956527007E5DD6 /* ASRangeHandlerRender.mm */; };
B350622D1B010EFD0018CF92 /* ASScrollDirection.h in Headers */ = {isa = PBXBuildFile; fileRef = 296A0A311A951715005ACEAA /* ASScrollDirection.h */; settings = {ATTRIBUTES = (Public, ); }; };
B35062391B010EFD0018CF92 /* ASThread.h in Headers */ = {isa = PBXBuildFile; fileRef = 058D0A12195D050800B7D73C /* ASThread.h */; settings = {ATTRIBUTES = (Public, ); }; };
B350623A1B010EFD0018CF92 /* NSMutableAttributedString+TextKitAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 058D09F5195D050800B7D73C /* NSMutableAttributedString+TextKitAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; };
@ -495,10 +481,6 @@
DECBD6E81BE56E1900CF4905 /* ASButtonNode.h in Headers */ = {isa = PBXBuildFile; fileRef = DECBD6E51BE56E1900CF4905 /* ASButtonNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
DECBD6E91BE56E1900CF4905 /* ASButtonNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = DECBD6E61BE56E1900CF4905 /* ASButtonNode.mm */; };
DECBD6EA1BE56E1900CF4905 /* ASButtonNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = DECBD6E61BE56E1900CF4905 /* ASButtonNode.mm */; };
DECC2ECD1C35C1C600388446 /* ASRangeControllerBeta.h in Headers */ = {isa = PBXBuildFile; fileRef = DECC2ECB1C35C1C600388446 /* ASRangeControllerBeta.h */; };
DECC2ECE1C35C1C600388446 /* ASRangeControllerBeta.h in Headers */ = {isa = PBXBuildFile; fileRef = DECC2ECB1C35C1C600388446 /* ASRangeControllerBeta.h */; };
DECC2ECF1C35C1C600388446 /* ASRangeControllerBeta.mm in Sources */ = {isa = PBXBuildFile; fileRef = DECC2ECC1C35C1C600388446 /* ASRangeControllerBeta.mm */; };
DECC2ED01C35C1C600388446 /* ASRangeControllerBeta.mm in Sources */ = {isa = PBXBuildFile; fileRef = DECC2ECC1C35C1C600388446 /* ASRangeControllerBeta.mm */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -688,17 +670,10 @@
257754BB1BEE458E00737CA5 /* ASTextKitCoreTextAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTextKitCoreTextAdditions.h; path = TextKit/ASTextKitCoreTextAdditions.h; sourceTree = "<group>"; };
257754BC1BEE458E00737CA5 /* ASTextNodeTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTextNodeTypes.h; path = TextKit/ASTextNodeTypes.h; sourceTree = "<group>"; };
257754BD1BEE458E00737CA5 /* ASTextNodeWordKerner.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ASTextNodeWordKerner.m; path = TextKit/ASTextNodeWordKerner.m; sourceTree = "<group>"; };
258FF4251C0D152600A83844 /* ASRangeHandlerVisible.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASRangeHandlerVisible.h; sourceTree = "<group>"; };
258FF4261C0D152600A83844 /* ASRangeHandlerVisible.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASRangeHandlerVisible.mm; sourceTree = "<group>"; };
25E327541C16819500A2170C /* ASPagerNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = ASPagerNode.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
25E327551C16819500A2170C /* ASPagerNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = ASPagerNode.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
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 /* ASRangeHandlerPreload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASRangeHandlerPreload.h; sourceTree = "<group>"; };
292C599B1A956527007E5DD6 /* ASRangeHandlerPreload.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASRangeHandlerPreload.mm; sourceTree = "<group>"; };
292C599C1A956527007E5DD6 /* ASRangeHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASRangeHandler.h; sourceTree = "<group>"; };
292C599D1A956527007E5DD6 /* ASRangeHandlerRender.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASRangeHandlerRender.h; sourceTree = "<group>"; };
292C599E1A956527007E5DD6 /* ASRangeHandlerRender.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASRangeHandlerRender.mm; sourceTree = "<group>"; };
2967F9E11AB0A4CF0072E4AB /* ASBasicImageDownloaderInternal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ASBasicImageDownloaderInternal.h; sourceTree = "<group>"; };
296A0A311A951715005ACEAA /* ASScrollDirection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASScrollDirection.h; path = AsyncDisplayKit/Details/ASScrollDirection.h; sourceTree = SOURCE_ROOT; };
296A0A341A951ABF005ACEAA /* ASBatchFetchingTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASBatchFetchingTests.m; sourceTree = "<group>"; };
@ -817,8 +792,6 @@
DEC146B51C37A16A004A0EE7 /* ASCollectionInternal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ASCollectionInternal.m; path = Details/ASCollectionInternal.m; sourceTree = "<group>"; };
DECBD6E51BE56E1900CF4905 /* ASButtonNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASButtonNode.h; sourceTree = "<group>"; };
DECBD6E61BE56E1900CF4905 /* ASButtonNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASButtonNode.mm; sourceTree = "<group>"; };
DECC2ECB1C35C1C600388446 /* ASRangeControllerBeta.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASRangeControllerBeta.h; sourceTree = "<group>"; };
DECC2ECC1C35C1C600388446 /* ASRangeControllerBeta.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASRangeControllerBeta.mm; sourceTree = "<group>"; };
EFA731F0396842FF8AB635EE /* libPods-AsyncDisplayKitTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-AsyncDisplayKitTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
FB07EABBCF28656C6297BC2D /* Pods-AsyncDisplayKitTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AsyncDisplayKitTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-AsyncDisplayKitTests/Pods-AsyncDisplayKitTests.debug.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
@ -1097,15 +1070,6 @@
058D09E9195D050800B7D73C /* ASMutableAttributedStringBuilder.m */,
055F1A3619ABD413004DAFF1 /* ASRangeController.h */,
055F1A3719ABD413004DAFF1 /* ASRangeController.mm */,
DECC2ECB1C35C1C600388446 /* ASRangeControllerBeta.h */,
DECC2ECC1C35C1C600388446 /* ASRangeControllerBeta.mm */,
292C599C1A956527007E5DD6 /* ASRangeHandler.h */,
258FF4251C0D152600A83844 /* ASRangeHandlerVisible.h */,
258FF4261C0D152600A83844 /* ASRangeHandlerVisible.mm */,
292C599A1A956527007E5DD6 /* ASRangeHandlerPreload.h */,
292C599B1A956527007E5DD6 /* ASRangeHandlerPreload.mm */,
292C599D1A956527007E5DD6 /* ASRangeHandlerRender.h */,
292C599E1A956527007E5DD6 /* ASRangeHandlerRender.mm */,
296A0A311A951715005ACEAA /* ASScrollDirection.h */,
205F0E111B371BD7007741D0 /* ASScrollDirection.m */,
058D0A12195D050800B7D73C /* ASThread.h */,
@ -1368,7 +1332,6 @@
DECBD6E71BE56E1900CF4905 /* ASButtonNode.h in Headers */,
DBC452DB1C5BF64600B16017 /* NSArray+Diffing.h in Headers */,
058D0A4C195D05CB00B7D73C /* ASDisplayNode+Subclasses.h in Headers */,
258FF4271C0D152600A83844 /* ASRangeHandlerVisible.h in Headers */,
058D0A4A195D05CB00B7D73C /* ASDisplayNode.h in Headers */,
058D0A84195D060300B7D73C /* ASDisplayNodeExtraIvars.h in Headers */,
AC7A2C171BDE11DF0093FE1A /* ASTableViewInternal.h in Headers */,
@ -1399,7 +1362,6 @@
9C65A72A1BA8EA4D0084DA91 /* ASLayoutOptionsPrivate.h in Headers */,
292C599F1A956527007E5DD6 /* ASLayoutRangeType.h in Headers */,
257754B61BEE44CD00737CA5 /* ASEqualityHashHelpers.h in Headers */,
DECC2ECD1C35C1C600388446 /* ASRangeControllerBeta.h in Headers */,
ACF6ED261B17843500DA7C62 /* ASLayoutSpec.h in Headers */,
ACF6ED4D1B17847A00DA7C62 /* ASLayoutSpecUtilities.h in Headers */,
AC026B6F1BD57DBF00BBC17E /* _ASHierarchyChangeSet.h in Headers */,
@ -1412,9 +1374,6 @@
055B9FA81A1C154B00035D6D /* ASNetworkImageNode.h in Headers */,
ACF6ED2B1B17843500DA7C62 /* ASOverlayLayoutSpec.h in Headers */,
055F1A3819ABD413004DAFF1 /* ASRangeController.h in Headers */,
292C59A21A956527007E5DD6 /* ASRangeHandler.h in Headers */,
292C59A01A956527007E5DD6 /* ASRangeHandlerPreload.h in Headers */,
292C59A31A956527007E5DD6 /* ASRangeHandlerRender.h in Headers */,
ACF6ED2D1B17843500DA7C62 /* ASRatioLayoutSpec.h in Headers */,
AC47D9451B3BB41900AAEE9D /* ASRelativeSize.h in Headers */,
291B63FB1AA53A7A000A71B3 /* ASScrollDirection.h in Headers */,
@ -1456,13 +1415,11 @@
buildActionMask = 2147483647;
files = (
AC026B6A1BD57D6F00BBC17E /* ASChangeSetDataController.h in Headers */,
25BAA16F1C0D18D2002747C7 /* ASRangeHandlerVisible.h in Headers */,
B35062481B010EFD0018CF92 /* _AS-objc-internal.h in Headers */,
B350623C1B010EFD0018CF92 /* _ASAsyncTransaction.h in Headers */,
B350623E1B010EFD0018CF92 /* _ASAsyncTransactionContainer+Private.h in Headers */,
B350623F1B010EFD0018CF92 /* _ASAsyncTransactionContainer.h in Headers */,
B13CA1011C52004900E031AB /* ASCollectionNode+Beta.h in Headers */,
DECC2ECE1C35C1C600388446 /* ASRangeControllerBeta.h in Headers */,
254C6B7E1BF94DF4003EC431 /* ASTextKitTailTruncater.h in Headers */,
B35062411B010EFD0018CF92 /* _ASAsyncTransactionGroup.h in Headers */,
B35062491B010EFD0018CF92 /* _ASCoreAnimationExtras.h in Headers */,
@ -1541,9 +1498,6 @@
B35062061B010EFD0018CF92 /* ASNetworkImageNode.h in Headers */,
34EFC76C1B701CED00AD841F /* ASOverlayLayoutSpec.h in Headers */,
B35062261B010EFD0018CF92 /* ASRangeController.h in Headers */,
B35062281B010EFD0018CF92 /* ASRangeHandler.h in Headers */,
B35062291B010EFD0018CF92 /* ASRangeHandlerPreload.h in Headers */,
B350622B1B010EFD0018CF92 /* ASRangeHandlerRender.h in Headers */,
34EFC76E1B701CF400AD841F /* ASRatioLayoutSpec.h in Headers */,
34EFC7651B701CCC00AD841F /* ASRelativeSize.h in Headers */,
254C6B741BF94DF4003EC431 /* ASTextNodeWordKerner.h in Headers */,
@ -1838,8 +1792,6 @@
257754AB1BEE44CD00737CA5 /* ASTextKitEntityAttribute.m in Sources */,
055F1A3919ABD413004DAFF1 /* ASRangeController.mm in Sources */,
044285091BAA63FE00D16268 /* ASBatchFetching.m in Sources */,
292C59A11A956527007E5DD6 /* ASRangeHandlerPreload.mm in Sources */,
292C59A41A956527007E5DD6 /* ASRangeHandlerRender.mm in Sources */,
257754AE1BEE44CD00737CA5 /* ASTextKitRenderer+Positioning.mm in Sources */,
ACF6ED2E1B17843500DA7C62 /* ASRatioLayoutSpec.mm in Sources */,
AC47D9461B3BB41900AAEE9D /* ASRelativeSize.mm in Sources */,
@ -1847,13 +1799,11 @@
D785F6631A74327E00291744 /* ASScrollNode.m in Sources */,
058D0A2C195D050800B7D73C /* ASSentinel.m in Sources */,
9C8221971BA237B80037F19A /* ASStackBaselinePositionedLayout.mm in Sources */,
258FF4281C0D152600A83844 /* ASRangeHandlerVisible.mm in Sources */,
251B8EF81BBB3D690087C538 /* ASCollectionDataController.mm in Sources */,
ACF6ED301B17843500DA7C62 /* ASStackLayoutSpec.mm in Sources */,
257754BE1BEE458E00737CA5 /* ASTextKitHelpers.mm in Sources */,
257754A91BEE44CD00737CA5 /* ASTextKitContext.mm in Sources */,
ACF6ED501B17847A00DA7C62 /* ASStackPositionedLayout.mm in Sources */,
DECC2ECF1C35C1C600388446 /* ASRangeControllerBeta.mm in Sources */,
ACF6ED521B17847A00DA7C62 /* ASStackUnpositionedLayout.mm in Sources */,
257754A61BEE44CD00737CA5 /* ASTextKitAttributes.mm in Sources */,
ACF6ED321B17843500DA7C62 /* ASStaticLayoutSpec.mm in Sources */,
@ -1977,20 +1927,16 @@
044285101BAA64EC00D16268 /* ASMultidimensionalArrayUtils.mm in Sources */,
B35062271B010EFD0018CF92 /* ASRangeController.mm in Sources */,
0442850A1BAA63FE00D16268 /* ASBatchFetching.m in Sources */,
B350622A1B010EFD0018CF92 /* ASRangeHandlerPreload.mm in Sources */,
B350622C1B010EFD0018CF92 /* ASRangeHandlerRender.mm in Sources */,
34EFC76F1B701CF700AD841F /* ASRatioLayoutSpec.mm in Sources */,
254C6B8B1BF94F8A003EC431 /* ASTextKitShadower.mm in Sources */,
34EFC7661B701CD200AD841F /* ASRelativeSize.mm in Sources */,
254C6B851BF94F8A003EC431 /* ASTextKitAttributes.mm in Sources */,
509E68601B3AED8E009B9150 /* ASScrollDirection.m in Sources */,
25A977EF1C0D2A5500406B62 /* ASRangeHandlerVisible.mm in Sources */,
B35062091B010EFD0018CF92 /* ASScrollNode.m in Sources */,
B35062561B010EFD0018CF92 /* ASSentinel.m in Sources */,
9C8221981BA237B80037F19A /* ASStackBaselinePositionedLayout.mm in Sources */,
34EFC7721B701D0300AD841F /* ASStackLayoutSpec.mm in Sources */,
34EFC7761B701D2A00AD841F /* ASStackPositionedLayout.mm in Sources */,
DECC2ED01C35C1C600388446 /* ASRangeControllerBeta.mm in Sources */,
34EFC7781B701D3100AD841F /* ASStackUnpositionedLayout.mm in Sources */,
AC026B6C1BD57D6F00BBC17E /* ASChangeSetDataController.m in Sources */,
34EFC7741B701D0A00AD841F /* ASStaticLayoutSpec.mm in Sources */,

View File

@ -167,12 +167,9 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
self.strongCollectionNode = collectionNode;
}
_layoutController = [ASDisplayNode shouldUseNewRenderingRange] ?
[[ASCollectionViewLayoutControllerBeta alloc] initWithCollectionView:self] :
[[ASCollectionViewLayoutControllerStable alloc] initWithCollectionView:self];
_layoutController = [[ASCollectionViewLayoutController alloc] initWithCollectionView:self];
_rangeController = [ASDisplayNode shouldUseNewRenderingRange] ? [[ASRangeControllerBeta alloc] init]
: [[ASRangeControllerStable alloc] init];
_rangeController = [[ASRangeController alloc] init];
_rangeController.dataSource = self;
_rangeController.delegate = self;
_rangeController.layoutController = _layoutController;

View File

@ -8,9 +8,6 @@
@interface ASDisplayNode (Beta)
+ (BOOL)shouldUseNewRenderingRange;
+ (void)setShouldUseNewRenderingRange:(BOOL)shouldUseNewRenderingRange;
+ (BOOL)usesImplicitHierarchyManagement;
+ (void)setUsesImplicitHierarchyManagement:(BOOL)enabled;

View File

@ -256,7 +256,6 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
+ (void)scheduleNodeForRecursiveDisplay:(ASDisplayNode *)node
{
ASDisplayNodeAssertMainThread();
ASDisplayNodeAssert([ASDisplayNode shouldUseNewRenderingRange], @"+scheduleNodeForRecursiveDisplay: should never be called without the new rendering range enabled");
static NSMutableSet *nodesToDisplay = nil;
static BOOL displayScheduled = NO;
static ASDN::RecursiveMutex displaySchedulerLock;
@ -1666,18 +1665,6 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
return _flags.shouldBypassEnsureDisplay;
}
static BOOL ShouldUseNewRenderingRange = YES;
+ (BOOL)shouldUseNewRenderingRange
{
return ShouldUseNewRenderingRange;
}
+ (void)setShouldUseNewRenderingRange:(BOOL)shouldUseNewRenderingRange
{
ShouldUseNewRenderingRange = shouldUseNewRenderingRange;
}
#pragma mark - For Subclasses
- (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize
@ -1922,7 +1909,7 @@ static BOOL ShouldUseNewRenderingRange = YES;
} else {
// NOTE: This case isn't currently supported as setInterfaceState: isn't exposed externally, and all
// internal use cases are range-managed. When a node is visible, don't mess with display - CA will start it.
if ([ASDisplayNode shouldUseNewRenderingRange] && !ASInterfaceStateIncludesVisible(newState)) {
if (!ASInterfaceStateIncludesVisible(newState)) {
// Check __implementsDisplay purely for efficiency - it's faster even than calling -asyncLayer.
if ([self __implementsDisplay]) {
if (nowDisplay) {

View File

@ -11,7 +11,6 @@
#import "ASAssert.h"
#import "ASBatchFetching.h"
#import "ASChangeSetDataController.h"
#import "ASCollectionViewLayoutController.h"
#import "ASDelegateProxy.h"
#import "ASDisplayNode+Beta.h"
#import "ASDisplayNode+FrameworkPrivate.h"
@ -148,8 +147,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
{
_layoutController = [[ASFlowLayoutController alloc] initWithScrollOption:ASFlowLayoutDirectionVertical];
_rangeController = [ASDisplayNode shouldUseNewRenderingRange] ? [[ASRangeControllerBeta alloc] init]
: [[ASRangeControllerStable alloc] init];
_rangeController = [[ASRangeController alloc] init];
_rangeController.layoutController = _layoutController;
_rangeController.dataSource = self;
_rangeController.delegate = self;

View File

@ -63,9 +63,6 @@
#import <AsyncDisplayKit/ASLayoutOptions.h>
#import <AsyncDisplayKit/ASLog.h>
#import <AsyncDisplayKit/ASMutableAttributedStringBuilder.h>
#import <AsyncDisplayKit/ASRangeHandler.h>
#import <AsyncDisplayKit/ASRangeHandlerPreload.h>
#import <AsyncDisplayKit/ASRangeHandlerRender.h>
#import <AsyncDisplayKit/ASThread.h>
#import <AsyncDisplayKit/CGRect+ASConvenience.h>
#import <AsyncDisplayKit/NSMutableAttributedString+TextKitAdditions.h>

View File

@ -82,13 +82,6 @@ extern BOOL ASRangeTuningParametersEqualToRangeTuningParameters(ASRangeTuningPar
#pragma mark - Abstract Index Path Range Support
// FIXME: This method can be removed once ASRangeControllerBeta becomes the main version.
- (BOOL)shouldUpdateForVisibleIndexPaths:(NSArray *)indexPaths rangeType:(ASLayoutRangeType)rangeType
{
ASDisplayNodeAssertNotSupported();
return NO;
}
- (NSSet *)indexPathsForScrolling:(ASScrollDirection)scrollDirection rangeMode:(ASLayoutRangeMode)rangeMode rangeType:(ASLayoutRangeType)rangeType
{
ASDisplayNodeAssertNotSupported();

View File

@ -19,10 +19,4 @@ NS_ASSUME_NONNULL_BEGIN
@end
@interface ASCollectionViewLayoutControllerStable : ASCollectionViewLayoutController
@end
@interface ASCollectionViewLayoutControllerBeta : ASCollectionViewLayoutController
@end
NS_ASSUME_NONNULL_END

View File

@ -49,90 +49,6 @@ typedef struct ASRangeGeometry ASRangeGeometry;
return self;
}
@end
@implementation ASCollectionViewLayoutControllerStable
{
std::vector<CGRect> _updateRangeBoundsIndexedByRangeType;
}
- (instancetype)initWithCollectionView:(ASCollectionView *)collectionView
{
if (!(self = [super initWithCollectionView:collectionView])) {
return nil;
}
_updateRangeBoundsIndexedByRangeType = std::vector<CGRect>(ASLayoutRangeTypeCount);
return self;
}
- (NSSet *)indexPathsForScrolling:(ASScrollDirection)scrollDirection rangeMode:(ASLayoutRangeMode)rangeMode rangeType:(ASLayoutRangeType)rangeType
{
ASRangeTuningParameters tuningParameters = [self tuningParametersForRangeMode:rangeMode rangeType:rangeType];
ASRangeGeometry rangeGeometry = [self rangeGeometryWithScrollDirection:scrollDirection tuningParameters:tuningParameters];
_updateRangeBoundsIndexedByRangeType[rangeType] = rangeGeometry.updateBounds;
return [self indexPathsForItemsWithinRangeBounds:rangeGeometry.rangeBounds];
}
- (NSSet *)indexPathsForItemsWithinRangeBounds:(CGRect)rangeBounds
{
NSMutableSet *indexPathSet = [[NSMutableSet alloc] init];
NSArray *layoutAttributes = [_collectionViewLayout layoutAttributesForElementsInRect:rangeBounds];
for (UICollectionViewLayoutAttributes *la in layoutAttributes) {
if (la.representedElementCategory == UICollectionElementCategoryCell) {
[indexPathSet addObject:la.indexPath];
}
}
return indexPathSet;
}
- (ASRangeGeometry)rangeGeometryWithScrollDirection:(ASScrollDirection)scrollDirection
tuningParameters:(ASRangeTuningParameters)tuningParameters
{
CGRect rangeBounds = _collectionView.bounds;
CGRect updateBounds = _collectionView.bounds;
// Scrollable directions can change for non-flow layouts
if ([_collectionViewLayout asdk_isFlowLayout] == NO) {
_scrollableDirections = [_collectionView scrollableDirections];
}
rangeBounds = CGRectExpandToRangeWithScrollableDirections(rangeBounds, tuningParameters, _scrollableDirections, scrollDirection);
ASRangeTuningParameters updateTuningParameters = tuningParameters;
updateTuningParameters.leadingBufferScreenfuls = MIN(updateTuningParameters.leadingBufferScreenfuls * 0.5, 0.95);
updateTuningParameters.trailingBufferScreenfuls = MIN(updateTuningParameters.trailingBufferScreenfuls * 0.5, 0.95);
updateBounds = CGRectExpandToRangeWithScrollableDirections(updateBounds, updateTuningParameters, _scrollableDirections, scrollDirection);
return {rangeBounds, updateBounds};
}
- (BOOL)shouldUpdateForVisibleIndexPaths:(NSArray *)indexPaths rangeType:(ASLayoutRangeType)rangeType
{
CGSize viewportSize = [self viewportSize];
CGRect updateRangeBounds = _updateRangeBoundsIndexedByRangeType[rangeType];
if (CGRectIsEmpty(updateRangeBounds)) {
return YES;
}
CGRect currentBounds = _collectionView.bounds;
if (CGRectIsEmpty(currentBounds)) {
currentBounds = CGRectMake(0, 0, viewportSize.width, viewportSize.height);
}
if (CGRectContainsRect(updateRangeBounds, currentBounds)) {
return NO;
} else {
return YES;
}
}
@end
@implementation ASCollectionViewLayoutControllerBeta
- (NSSet *)indexPathsForScrolling:(ASScrollDirection)scrollDirection rangeMode:(ASLayoutRangeMode)rangeMode rangeType:(ASLayoutRangeType)rangeType
{
ASRangeTuningParameters tuningParameters = [self tuningParametersForRangeMode:rangeMode rangeType:rangeType];

View File

@ -15,8 +15,6 @@
#include <vector>
#include <cassert>
static const CGFloat kASFlowLayoutControllerRefreshingThreshold = 0.3;
@interface ASFlowLayoutController()
{
ASIndexPathRange _visibleRange;
@ -39,32 +37,6 @@ static const CGFloat kASFlowLayoutControllerRefreshingThreshold = 0.3;
#pragma mark - Visible Indices
// FIXME: This method can be removed once ASRangeControllerBeta becomes the main version.
- (BOOL)shouldUpdateForVisibleIndexPaths:(NSArray *)indexPaths rangeType:(ASLayoutRangeType)rangeType
{
if (!indexPaths.count || rangeType >= _rangesByType.size()) {
return NO;
}
ASIndexPathRange existingRange = _rangesByType[rangeType];
ASIndexPathRange newRange = [self indexPathRangeForIndexPaths:indexPaths];
ASIndexPath maximumStart = ASIndexPathMaximum(existingRange.start, newRange.start);
ASIndexPath minimumEnd = ASIndexPathMinimum(existingRange.end, newRange.end);
if (ASIndexPathEqualToIndexPath(maximumStart, existingRange.start) || ASIndexPathEqualToIndexPath(minimumEnd, existingRange.end)) {
return YES;
}
NSInteger newStartDelta = [self flowLayoutDistanceForRange:ASIndexPathRangeMake(_visibleRange.start, newRange.start)];
NSInteger existingStartDelta = [self flowLayoutDistanceForRange:ASIndexPathRangeMake(_visibleRange.start, existingRange.start)] * kASFlowLayoutControllerRefreshingThreshold;
NSInteger newEndDelta = [self flowLayoutDistanceForRange:ASIndexPathRangeMake(_visibleRange.end, newRange.end)];
NSInteger existingEndDelta = [self flowLayoutDistanceForRange:ASIndexPathRangeMake(_visibleRange.end, existingRange.end)] * kASFlowLayoutControllerRefreshingThreshold;
return (newStartDelta > existingStartDelta) || (newEndDelta > existingEndDelta);
}
- (void)setVisibleNodeIndexPaths:(NSArray *)indexPaths
{
_visibleRange = [self indexPathRangeForIndexPaths:indexPaths];

View File

@ -31,10 +31,6 @@ FOUNDATION_EXPORT BOOL ASRangeTuningParametersEqualToRangeTuningParameters(ASRan
- (ASRangeTuningParameters)tuningParametersForRangeMode:(ASLayoutRangeMode)rangeMode rangeType:(ASLayoutRangeType)rangeType;
// FIXME: This method can be removed once ASRangeControllerBeta becomes the main version.
// TODO: Now that it is the main version, can we remove this now?
- (BOOL)shouldUpdateForVisibleIndexPaths:(NSArray<NSIndexPath *> *)indexPaths rangeType:(ASLayoutRangeType)rangeType;
- (NSSet *)indexPathsForScrolling:(ASScrollDirection)scrollDirection rangeMode:(ASLayoutRangeMode)rangeMode rangeType:(ASLayoutRangeType)rangeType;
@optional

View File

@ -77,12 +77,6 @@ NS_ASSUME_NONNULL_BEGIN
@end
@interface ASRangeControllerStable : ASRangeController
@end
@interface ASRangeControllerBeta : ASRangeController
@end
/**
* Data source for ASRangeController.
*

View File

@ -10,51 +10,26 @@
#import "ASAssert.h"
#import "ASDisplayNodeExtras.h"
#import "ASDisplayNodeInternal.h"
#import "ASMultiDimensionalArrayUtils.h"
#import "ASRangeHandlerVisible.h"
#import "ASRangeHandlerRender.h"
#import "ASRangeHandlerPreload.h"
#import "ASInternalHelpers.h"
#import "ASLayoutController.h"
#import "ASLayoutRangeType.h"
#import "ASDisplayNode+FrameworkPrivate.h"
@implementation ASRangeController
- (void)visibleNodeIndexPathsDidChangeWithScrollDirection:(ASScrollDirection)scrollDirection
{
}
- (void)configureContentView:(UIView *)contentView forCellNode:(ASCellNode *)node
{
}
- (void)setTuningParameters:(ASRangeTuningParameters)tuningParameters forRangeMode:(ASLayoutRangeMode)rangeMode rangeType:(ASLayoutRangeType)rangeType
{
[_layoutController setTuningParameters:tuningParameters forRangeMode:rangeMode rangeType:rangeType];
}
- (ASRangeTuningParameters)tuningParametersForRangeMode:(ASLayoutRangeMode)rangeMode rangeType:(ASLayoutRangeType)rangeType
{
return [_layoutController tuningParametersForRangeMode:rangeMode rangeType:rangeType];
}
@end
@interface ASRangeControllerStable ()
@interface ASRangeController ()
{
BOOL _rangeIsValid;
// keys should be ASLayoutRangeTypes and values NSSets containing NSIndexPaths
NSMutableDictionary *_rangeTypeIndexPaths;
NSDictionary *_rangeTypeHandlers;
BOOL _queuedRangeUpdate;
BOOL _layoutControllerImplementsSetVisibleIndexPaths;
ASScrollDirection _scrollDirection;
NSSet<NSIndexPath *> *_allPreviousIndexPaths;
ASLayoutRangeMode _currentRangeMode;
BOOL _didRegisterForNotifications;
CFAbsoluteTime _pendingDisplayNodesTimestamp;
}
@end
@implementation ASRangeControllerStable
@implementation ASRangeController
- (instancetype)init
{
@ -63,19 +38,273 @@
}
_rangeIsValid = YES;
_rangeTypeIndexPaths = [NSMutableDictionary dictionary];
_rangeTypeHandlers = @{
@(ASLayoutRangeTypeDisplay) : [[ASRangeHandlerRender alloc] init],
@(ASLayoutRangeTypeFetchData): [[ASRangeHandlerPreload alloc] init],
};
_currentRangeMode = ASLayoutRangeModeInvalid;
return self;
}
- (void)dealloc
{
if (_didRegisterForNotifications) {
[[NSNotificationCenter defaultCenter] removeObserver:self name:ASRenderingEngineDidDisplayScheduledNodesNotification object:nil];
}
}
#pragma mark - Core visible node range managment API
+ (ASLayoutRangeMode)rangeModeForInterfaceState:(ASInterfaceState)interfaceState
currentRangeMode:(ASLayoutRangeMode)currentRangeMode
{
BOOL isVisible = (ASInterfaceStateIncludesVisible(interfaceState));
BOOL isFirstRangeUpdate = (currentRangeMode == ASLayoutRangeModeInvalid);
if (!isVisible || isFirstRangeUpdate) {
return ASLayoutRangeModeMinimum;
}
return ASLayoutRangeModeFull;
}
- (void)visibleNodeIndexPathsDidChangeWithScrollDirection:(ASScrollDirection)scrollDirection
{
_scrollDirection = scrollDirection;
[self scheduleRangeUpdate];
}
- (void)scheduleRangeUpdate
{
if (_queuedRangeUpdate) {
return;
}
// coalesce these events -- handling them multiple times per runloop is noisy and expensive
_queuedRangeUpdate = YES;
dispatch_async(dispatch_get_main_queue(), ^{
[self _updateVisibleNodeIndexPaths];
});
}
- (void)setLayoutController:(id<ASLayoutController>)layoutController
{
_layoutController = layoutController;
_layoutControllerImplementsSetVisibleIndexPaths = [_layoutController respondsToSelector:@selector(setVisibleNodeIndexPaths:)];
}
- (void)_updateVisibleNodeIndexPaths
{
ASDisplayNodeAssert(_layoutController, @"An ASLayoutController is required by ASRangeController");
if (!_queuedRangeUpdate || !_layoutController) {
return;
}
// TODO: Consider if we need to use this codepath, or can rely on something more similar to the data & display ranges
// Example: ... = [_layoutController indexPathsForScrolling:_scrollDirection rangeType:ASLayoutRangeTypeVisible];
NSArray<NSIndexPath *> *visibleNodePaths = [_dataSource visibleNodeIndexPathsForRangeController:self];
if (visibleNodePaths.count == 0) { // if we don't have any visibleNodes currently (scrolled before or after content)...
_queuedRangeUpdate = NO;
return; // don't do anything for this update, but leave _rangeIsValid == NO to make sure we update it later
}
[_layoutController setViewportSize:[_dataSource viewportSizeForRangeController:self]];
// the layout controller needs to know what the current visible indices are to calculate range offsets
if (_layoutControllerImplementsSetVisibleIndexPaths) {
[_layoutController setVisibleNodeIndexPaths:visibleNodePaths];
}
// allNodes is a 2D array: it contains arrays for each section, each containing nodes.
NSArray<NSArray *> *allNodes = [_dataSource completedNodes];
NSUInteger numberOfSections = [allNodes count];
NSArray<ASDisplayNode *> *currentSectionNodes = nil;
NSInteger currentSectionIndex = -1; // Set to -1 so we don't match any indexPath.section on the first iteration.
NSUInteger numberOfNodesInSection = 0;
NSSet<NSIndexPath *> *visibleIndexPaths = [NSSet setWithArray:visibleNodePaths];
NSSet<NSIndexPath *> *displayIndexPaths = nil;
NSSet<NSIndexPath *> *fetchDataIndexPaths = nil;
// Prioritize the order in which we visit each. Visible nodes should be updated first so they are enqueued on
// the network or display queues before preloading (offscreen) nodes are enqueued.
NSMutableOrderedSet<NSIndexPath *> *allIndexPaths = [[NSMutableOrderedSet alloc] initWithSet:visibleIndexPaths];
ASInterfaceState selfInterfaceState = [_dataSource interfaceStateForRangeController:self];
ASLayoutRangeMode rangeMode = [ASRangeController rangeModeForInterfaceState:selfInterfaceState
currentRangeMode:_currentRangeMode];
ASRangeTuningParameters parametersFetchData = [_layoutController tuningParametersForRangeMode:rangeMode
rangeType:ASLayoutRangeTypeFetchData];
if (ASRangeTuningParametersEqualToRangeTuningParameters(parametersFetchData, ASRangeTuningParametersZero)) {
fetchDataIndexPaths = visibleIndexPaths;
} else {
fetchDataIndexPaths = [_layoutController indexPathsForScrolling:_scrollDirection
rangeMode:rangeMode
rangeType:ASLayoutRangeTypeFetchData];
}
ASRangeTuningParameters parametersDisplay = [_layoutController tuningParametersForRangeMode:rangeMode
rangeType:ASLayoutRangeTypeDisplay];
if (ASRangeTuningParametersEqualToRangeTuningParameters(parametersDisplay, ASRangeTuningParametersZero)) {
displayIndexPaths = visibleIndexPaths;
} else if (ASRangeTuningParametersEqualToRangeTuningParameters(parametersDisplay, parametersFetchData)) {
displayIndexPaths = fetchDataIndexPaths;
} else {
displayIndexPaths = [_layoutController indexPathsForScrolling:_scrollDirection
rangeMode:rangeMode
rangeType:ASLayoutRangeTypeDisplay];
}
// Typically the fetchDataIndexPaths 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.
[allIndexPaths unionSet:displayIndexPaths];
[allIndexPaths unionSet:fetchDataIndexPaths];
// Add anything we had applied interfaceState to in the last update, but is no longer in range, so we can clear any
// range flags it still has enabled. Most of the time, all but a few elements are equal; a large programmatic
// scroll or major main thread stall could cause entirely disjoint sets. In either case we must visit all.
// Calling "-set" on NSMutableOrderedSet just references the underlying mutable data store, so we must copy it.
NSSet<NSIndexPath *> *allCurrentIndexPaths = [[allIndexPaths set] copy];
[allIndexPaths unionSet:_allPreviousIndexPaths];
_allPreviousIndexPaths = allCurrentIndexPaths;
_currentRangeMode = rangeMode;
if (!_rangeIsValid) {
[allIndexPaths addObjectsFromArray:ASIndexPathsForMultidimensionalArray(allNodes)];
}
// TODO Don't register for notifications if this range update doesn't cause any node to enter rendering pipeline.
// This can be done once there is an API to observe to (or be notified upon) interface state changes or pipeline enterings
[self registerForNotificationsForInterfaceStateIfNeeded:selfInterfaceState];
#if RangeControllerLoggingEnabled
NSMutableArray<NSIndexPath *> *modifiedIndexPaths = (RangeControllerLoggingEnabled ? [NSMutableArray array] : nil);
#endif
for (NSIndexPath *indexPath in allIndexPaths) {
// Before a node / indexPath is exposed to ASRangeController, ASDataController should have already measured it.
// For consistency, make sure each node knows that it should measure itself if something changes.
ASInterfaceState interfaceState = ASInterfaceStateMeasureLayout;
if (ASInterfaceStateIncludesVisible(selfInterfaceState)) {
if ([fetchDataIndexPaths containsObject:indexPath]) {
interfaceState |= ASInterfaceStateFetchData;
}
if ([displayIndexPaths containsObject:indexPath]) {
interfaceState |= ASInterfaceStateDisplay;
}
if ([visibleIndexPaths containsObject:indexPath]) {
interfaceState |= ASInterfaceStateVisible;
}
} 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.
// We handle this as a separate case to minimize set operations for offscreen preloading, including containsObject:.
// Set Layout, Fetch Data, Display. 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.
if ([allCurrentIndexPaths containsObject:indexPath]) {
// We might be looking at an indexPath that was previously in-range, but now we need to clear it.
// In that case we'll just set it back to MeasureLayout. Only set Display | FetchData if in allCurrentIndexPaths.
interfaceState |= ASInterfaceStateDisplay;
interfaceState |= ASInterfaceStateFetchData;
}
}
NSInteger section = indexPath.section;
NSInteger row = indexPath.row;
if (section >= 0 && row >= 0 && section < numberOfSections) {
if (section != currentSectionIndex) {
// Often we'll be dealing with indexPaths in the same section, but the set isn't sorted and we may even bounce
// between the same ones. Still, this saves dozens of method calls to access the inner array and count.
currentSectionNodes = [allNodes objectAtIndex:section];
numberOfNodesInSection = [currentSectionNodes count];
currentSectionIndex = section;
}
if (row < numberOfNodesInSection) {
ASDisplayNode *node = [currentSectionNodes objectAtIndex:row];
ASDisplayNodeAssert(node.hierarchyState & ASHierarchyStateRangeManaged, @"All nodes reaching this point should be range-managed, or interfaceState may be incorrectly reset.");
// Skip the many method calls of the recursive operation if the top level cell node already has the right interfaceState.
if (node.interfaceState != interfaceState) {
#if RangeControllerLoggingEnabled
[modifiedIndexPaths addObject:indexPath];
#endif
[node recursivelySetInterfaceState:interfaceState];
}
}
}
}
if (_didRegisterForNotifications) {
_pendingDisplayNodesTimestamp = CFAbsoluteTimeGetCurrent();
}
_rangeIsValid = YES;
_queuedRangeUpdate = NO;
#if RangeControllerLoggingEnabled
NSSet *visibleNodePathsSet = [NSSet setWithArray:visibleNodePaths];
BOOL setsAreEqual = [visibleIndexPaths isEqualToSet:visibleNodePathsSet];
NSLog(@"visible sets are equal: %d", setsAreEqual);
if (!setsAreEqual) {
NSLog(@"standard: %@", visibleIndexPaths);
NSLog(@"custom: %@", visibleNodePathsSet);
}
[modifiedIndexPaths sortUsingSelector:@selector(compare:)];
for (NSIndexPath *indexPath in modifiedIndexPaths) {
ASDisplayNode *node = [_dataSource rangeController:self nodeAtIndexPath:indexPath];
ASInterfaceState interfaceState = node.interfaceState;
BOOL inVisible = ASInterfaceStateIncludesVisible(interfaceState);
BOOL inDisplay = ASInterfaceStateIncludesDisplay(interfaceState);
BOOL inFetchData = ASInterfaceStateIncludesFetchData(interfaceState);
NSLog(@"indexPath %@, Visible: %d, Display: %d, FetchData: %d", indexPath, inVisible, inDisplay, inFetchData);
}
#endif
}
#pragma mark - Notification observers
- (void)registerForNotificationsForInterfaceStateIfNeeded:(ASInterfaceState)interfaceState
{
if (!_didRegisterForNotifications) {
ASLayoutRangeMode nextRangeMode = [ASRangeController rangeModeForInterfaceState:interfaceState
currentRangeMode:_currentRangeMode];
if (_currentRangeMode != nextRangeMode) {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(scheduledNodesDidDisplay:)
name:ASRenderingEngineDidDisplayScheduledNodesNotification
object:nil];
_didRegisterForNotifications = YES;
}
}
}
- (void)scheduledNodesDidDisplay:(NSNotification *)notification
{
CFAbsoluteTime notificationTimestamp = ((NSNumber *)[notification.userInfo objectForKey:ASRenderingEngineDidDisplayNodesScheduledBeforeTimestamp]).doubleValue;
if (_pendingDisplayNodesTimestamp < notificationTimestamp) {
// The rendering engine has processed all the nodes this range controller scheduled. Let's schedule a range update
[[NSNotificationCenter defaultCenter] removeObserver:self name:ASRenderingEngineDidDisplayScheduledNodesNotification object:nil];
_didRegisterForNotifications = NO;
[self scheduleRangeUpdate];
}
}
#pragma mark - Cell node view handling
- (void)configureContentView:(UIView *)contentView forCellNode:(ASCellNode *)node
{
ASDisplayNodeAssertMainThread();
ASDisplayNodeAssert(node, @"Cannot move a nil node to a view");
ASDisplayNodeAssert(contentView, @"Cannot move a node to a non-existent view");
if (node.view.superview == contentView) {
// this content view is already correctly configured
return;
@ -86,119 +315,17 @@
[view removeFromSuperview];
}
[self moveCellNode:node toView:contentView];
[contentView addSubview:node.view];
}
- (void)moveCellNode:(ASCellNode *)node toView:(UIView *)view
- (void)setTuningParameters:(ASRangeTuningParameters)tuningParameters forRangeMode:(ASLayoutRangeMode)rangeMode rangeType:(ASLayoutRangeType)rangeType
{
ASDisplayNodeAssertMainThread();
ASDisplayNodeAssert(node, @"Cannot move a nil node to a view");
ASDisplayNodeAssert(view, @"Cannot move a node to a non-existent view");
// force any nodes that are about to come into view to have display enabled
if (node.displaySuspended) {
[node recursivelySetDisplaySuspended:NO];
}
[view addSubview:node.view];
[_layoutController setTuningParameters:tuningParameters forRangeMode:rangeMode rangeType:rangeType];
}
#pragma mark - Core visible node range managment API
- (void)visibleNodeIndexPathsDidChangeWithScrollDirection:(ASScrollDirection)scrollDirection
- (ASRangeTuningParameters)tuningParametersForRangeMode:(ASLayoutRangeMode)rangeMode rangeType:(ASLayoutRangeType)rangeType
{
_scrollDirection = scrollDirection;
if (_queuedRangeUpdate) {
return;
}
// coalesce these events -- handling them multiple times per runloop is noisy and expensive
_queuedRangeUpdate = YES;
[self performSelector:@selector(_updateVisibleNodeIndexPaths)
withObject:nil
afterDelay:0
inModes:@[ NSRunLoopCommonModes ]];
}
- (void)_updateVisibleNodeIndexPaths
{
if (!_queuedRangeUpdate) {
return;
}
NSArray *visibleNodePaths = [_dataSource visibleNodeIndexPathsForRangeController:self];
if (visibleNodePaths.count == 0) { // if we don't have any visibleNodes currently (scrolled before or after content)...
_queuedRangeUpdate = NO;
return ; // don't do anything for this update, but leave _rangeIsValid to make sure we update it later
}
NSSet *visibleNodePathsSet = [NSSet setWithArray:visibleNodePaths];
CGSize viewportSize = [_dataSource viewportSizeForRangeController:self];
[_layoutController setViewportSize:viewportSize];
// the layout controller needs to know what the current visible indices are to calculate range offsets
if ([_layoutController respondsToSelector:@selector(setVisibleNodeIndexPaths:)]) {
[_layoutController setVisibleNodeIndexPaths:visibleNodePaths];
}
for (NSInteger i = 0; i < ASLayoutRangeTypeCount; i++) {
ASLayoutRangeType rangeType = (ASLayoutRangeType)i;
id rangeKey = @(rangeType);
// this delegate decide what happens when a node is added or removed from a range
id<ASRangeHandler> rangeHandler = _rangeTypeHandlers[rangeKey];
if (!_rangeIsValid || [_layoutController shouldUpdateForVisibleIndexPaths:visibleNodePaths rangeType:rangeType]) {
NSSet *indexPaths = [_layoutController indexPathsForScrolling:_scrollDirection
rangeMode:ASLayoutRangeModeFull
rangeType:rangeType];
// Notify to remove indexpaths that are leftover that are not visible or included in the _layoutController calculated paths
NSMutableSet *removedIndexPaths = _rangeIsValid ? [_rangeTypeIndexPaths[rangeKey] mutableCopy] : [NSMutableSet set];
[removedIndexPaths minusSet:indexPaths];
[removedIndexPaths minusSet:visibleNodePathsSet];
if (removedIndexPaths.count) {
NSArray *removedNodes = [_dataSource rangeController:self nodesAtIndexPaths:[removedIndexPaths allObjects]];
for (ASCellNode *node in removedNodes) {
// 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.
[rangeHandler node:node exitedRangeOfType:rangeType];
}
}
// Notify to add index paths that are not currently in _rangeTypeIndexPaths
NSMutableSet *addedIndexPaths = [indexPaths mutableCopy];
[addedIndexPaths minusSet:_rangeTypeIndexPaths[rangeKey]];
// The preload range (for example) should include nodes that are visible
// TODO: remove this once we have removed the dependency on Core Animation's -display
if ([self shouldSkipVisibleNodesForRangeType:rangeType]) {
[addedIndexPaths minusSet:visibleNodePathsSet];
}
if (addedIndexPaths.count) {
NSArray *addedNodes = [_dataSource rangeController:self nodesAtIndexPaths:[addedIndexPaths allObjects]];
for (ASCellNode *node in addedNodes) {
[rangeHandler node:node enteredRangeOfType:rangeType];
}
}
// set the range indexpaths so that we can remove/add on the next update pass
_rangeTypeIndexPaths[rangeKey] = indexPaths;
}
}
_rangeIsValid = YES;
_queuedRangeUpdate = NO;
}
- (BOOL)shouldSkipVisibleNodesForRangeType:(ASLayoutRangeType)rangeType
{
return rangeType == ASLayoutRangeTypeDisplay;
return [_layoutController tuningParametersForRangeMode:rangeMode rangeType:rangeType];
}
#pragma mark - ASDataControllerDelegete
@ -230,18 +357,6 @@
{
ASPerformBlockOnMainThread(^{
_rangeIsValid = NO;
// When removing nodes we need to make sure that removed indexPaths are not left in _rangeTypeIndexPaths,
// otherwise _updateVisibleNodeIndexPaths may try to retrieve nodes from dataSource that aren't there anymore
for (NSInteger i = 0; i < ASLayoutRangeTypeCount; i++) {
id rangeKey = @((ASLayoutRangeType)i);
NSMutableSet *rangePaths = [_rangeTypeIndexPaths[rangeKey] mutableCopy];
for (NSIndexPath *path in indexPaths) {
[rangePaths removeObject:path];
}
_rangeTypeIndexPaths[rangeKey] = rangePaths;
}
[_delegate rangeController:self didDeleteNodes:nodes atIndexPaths:indexPaths withAnimationOptions:animationOptions];
});
}
@ -259,22 +374,8 @@
{
ASPerformBlockOnMainThread(^{
_rangeIsValid = NO;
// When removing nodes we need to make sure that removed indexPaths are not left in _rangeTypeIndexPaths,
// otherwise _updateVisibleNodeIndexPaths may try to retrieve nodes from dataSource that aren't there anymore
for (NSInteger i = 0; i < ASLayoutRangeTypeCount; i++) {
id rangeKey = @((ASLayoutRangeType)i);
NSMutableSet *rangePaths = [_rangeTypeIndexPaths[rangeKey] mutableCopy];
for (NSIndexPath *path in _rangeTypeIndexPaths[rangeKey]) {
if ([indexSet containsIndex:path.section]) {
[rangePaths removeObject:path];
}
}
_rangeTypeIndexPaths[rangeKey] = rangePaths;
}
[_delegate rangeController:self didDeleteSectionsAtIndexSet:indexSet withAnimationOptions:animationOptions];
});
}
@end
@end

View File

@ -1,20 +0,0 @@
/* 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/ASRangeController.h>
#import <AsyncDisplayKit/ASCellNode.h>
#import <AsyncDisplayKit/ASDataController.h>
#import <AsyncDisplayKit/ASLayoutController.h>
NS_ASSUME_NONNULL_BEGIN
// ASRangeControllerBeta defined in ASRangeController.h
NS_ASSUME_NONNULL_END

View File

@ -1,374 +0,0 @@
/* 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 "ASRangeControllerBeta.h"
#import "ASAssert.h"
#import "ASDisplayNodeExtras.h"
#import "ASDisplayNodeInternal.h"
#import "ASMultiDimensionalArrayUtils.h"
#import "ASRangeHandlerVisible.h"
#import "ASRangeHandlerRender.h"
#import "ASRangeHandlerPreload.h"
#import "ASInternalHelpers.h"
#import "ASDisplayNode+FrameworkPrivate.h"
@interface ASRangeControllerBeta ()
{
BOOL _rangeIsValid;
BOOL _queuedRangeUpdate;
BOOL _layoutControllerImplementsSetVisibleIndexPaths;
ASScrollDirection _scrollDirection;
NSSet<NSIndexPath *> *_allPreviousIndexPaths;
ASLayoutRangeMode _currentRangeMode;
BOOL _didRegisterForNotifications;
CFAbsoluteTime _pendingDisplayNodesTimestamp;
}
@end
@implementation ASRangeControllerBeta
- (instancetype)init
{
if (!(self = [super init])) {
return nil;
}
_rangeIsValid = YES;
_currentRangeMode = ASLayoutRangeModeInvalid;
return self;
}
- (void)dealloc
{
if (_didRegisterForNotifications) {
[[NSNotificationCenter defaultCenter] removeObserver:self name:ASRenderingEngineDidDisplayScheduledNodesNotification object:nil];
}
}
#pragma mark - Core visible node range managment API
+ (ASLayoutRangeMode)rangeModeForInterfaceState:(ASInterfaceState)interfaceState
currentRangeMode:(ASLayoutRangeMode)currentRangeMode
{
BOOL isVisible = (ASInterfaceStateIncludesVisible(interfaceState));
BOOL isFirstRangeUpdate = (currentRangeMode == ASLayoutRangeModeInvalid);
if (!isVisible || isFirstRangeUpdate) {
return ASLayoutRangeModeMinimum;
}
return ASLayoutRangeModeFull;
}
- (void)visibleNodeIndexPathsDidChangeWithScrollDirection:(ASScrollDirection)scrollDirection
{
_scrollDirection = scrollDirection;
[self scheduleRangeUpdate];
}
- (void)scheduleRangeUpdate
{
if (_queuedRangeUpdate) {
return;
}
// coalesce these events -- handling them multiple times per runloop is noisy and expensive
_queuedRangeUpdate = YES;
dispatch_async(dispatch_get_main_queue(), ^{
[self _updateVisibleNodeIndexPaths];
});
}
- (void)setLayoutController:(id<ASLayoutController>)layoutController
{
_layoutController = layoutController;
_layoutControllerImplementsSetVisibleIndexPaths = [_layoutController respondsToSelector:@selector(setVisibleNodeIndexPaths:)];
}
- (void)_updateVisibleNodeIndexPaths
{
ASDisplayNodeAssert(_layoutController, @"An ASLayoutController is required by ASRangeController");
if (!_queuedRangeUpdate || !_layoutController) {
return;
}
// TODO: Consider if we need to use this codepath, or can rely on something more similar to the data & display ranges
// Example: ... = [_layoutController indexPathsForScrolling:_scrollDirection rangeType:ASLayoutRangeTypeVisible];
NSArray<NSIndexPath *> *visibleNodePaths = [_dataSource visibleNodeIndexPathsForRangeController:self];
if (visibleNodePaths.count == 0) { // if we don't have any visibleNodes currently (scrolled before or after content)...
_queuedRangeUpdate = NO;
return; // don't do anything for this update, but leave _rangeIsValid == NO to make sure we update it later
}
[_layoutController setViewportSize:[_dataSource viewportSizeForRangeController:self]];
// the layout controller needs to know what the current visible indices are to calculate range offsets
if (_layoutControllerImplementsSetVisibleIndexPaths) {
[_layoutController setVisibleNodeIndexPaths:visibleNodePaths];
}
// allNodes is a 2D array: it contains arrays for each section, each containing nodes.
NSArray<NSArray *> *allNodes = [_dataSource completedNodes];
NSUInteger numberOfSections = [allNodes count];
NSArray<ASDisplayNode *> *currentSectionNodes = nil;
NSInteger currentSectionIndex = -1; // Set to -1 so we don't match any indexPath.section on the first iteration.
NSUInteger numberOfNodesInSection = 0;
NSSet<NSIndexPath *> *visibleIndexPaths = [NSSet setWithArray:visibleNodePaths];
NSSet<NSIndexPath *> *displayIndexPaths = nil;
NSSet<NSIndexPath *> *fetchDataIndexPaths = nil;
// Prioritize the order in which we visit each. Visible nodes should be updated first so they are enqueued on
// the network or display queues before preloading (offscreen) nodes are enqueued.
NSMutableOrderedSet<NSIndexPath *> *allIndexPaths = [[NSMutableOrderedSet alloc] initWithSet:visibleIndexPaths];
ASInterfaceState selfInterfaceState = [_dataSource interfaceStateForRangeController:self];
ASLayoutRangeMode rangeMode = [ASRangeControllerBeta rangeModeForInterfaceState:selfInterfaceState
currentRangeMode:_currentRangeMode];
ASRangeTuningParameters parametersFetchData = [_layoutController tuningParametersForRangeMode:rangeMode
rangeType:ASLayoutRangeTypeFetchData];
if (ASRangeTuningParametersEqualToRangeTuningParameters(parametersFetchData, ASRangeTuningParametersZero)) {
fetchDataIndexPaths = visibleIndexPaths;
} else {
fetchDataIndexPaths = [_layoutController indexPathsForScrolling:_scrollDirection
rangeMode:rangeMode
rangeType:ASLayoutRangeTypeFetchData];
}
ASRangeTuningParameters parametersDisplay = [_layoutController tuningParametersForRangeMode:rangeMode
rangeType:ASLayoutRangeTypeDisplay];
if (ASRangeTuningParametersEqualToRangeTuningParameters(parametersDisplay, ASRangeTuningParametersZero)) {
displayIndexPaths = visibleIndexPaths;
} else if (ASRangeTuningParametersEqualToRangeTuningParameters(parametersDisplay, parametersFetchData)) {
displayIndexPaths = fetchDataIndexPaths;
} else {
displayIndexPaths = [_layoutController indexPathsForScrolling:_scrollDirection
rangeMode:rangeMode
rangeType:ASLayoutRangeTypeDisplay];
}
// Typically the fetchDataIndexPaths 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.
[allIndexPaths unionSet:displayIndexPaths];
[allIndexPaths unionSet:fetchDataIndexPaths];
// Add anything we had applied interfaceState to in the last update, but is no longer in range, so we can clear any
// range flags it still has enabled. Most of the time, all but a few elements are equal; a large programmatic
// scroll or major main thread stall could cause entirely disjoint sets. In either case we must visit all.
// Calling "-set" on NSMutableOrderedSet just references the underlying mutable data store, so we must copy it.
NSSet<NSIndexPath *> *allCurrentIndexPaths = [[allIndexPaths set] copy];
[allIndexPaths unionSet:_allPreviousIndexPaths];
_allPreviousIndexPaths = allCurrentIndexPaths;
_currentRangeMode = rangeMode;
if (!_rangeIsValid) {
[allIndexPaths addObjectsFromArray:ASIndexPathsForMultidimensionalArray(allNodes)];
}
// TODO Don't register for notifications if this range update doesn't cause any node to enter rendering pipeline.
// This can be done once there is an API to observe to (or be notified upon) interface state changes or pipeline enterings
[self registerForNotificationsForInterfaceStateIfNeeded:selfInterfaceState];
#if RangeControllerLoggingEnabled
NSMutableArray<NSIndexPath *> *modifiedIndexPaths = (RangeControllerLoggingEnabled ? [NSMutableArray array] : nil);
#endif
for (NSIndexPath *indexPath in allIndexPaths) {
// Before a node / indexPath is exposed to ASRangeController, ASDataController should have already measured it.
// For consistency, make sure each node knows that it should measure itself if something changes.
ASInterfaceState interfaceState = ASInterfaceStateMeasureLayout;
if (ASInterfaceStateIncludesVisible(selfInterfaceState)) {
if ([fetchDataIndexPaths containsObject:indexPath]) {
interfaceState |= ASInterfaceStateFetchData;
}
if ([displayIndexPaths containsObject:indexPath]) {
interfaceState |= ASInterfaceStateDisplay;
}
if ([visibleIndexPaths containsObject:indexPath]) {
interfaceState |= ASInterfaceStateVisible;
}
} 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.
// We handle this as a separate case to minimize set operations for offscreen preloading, including containsObject:.
// Set Layout, Fetch Data, Display. 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.
if ([allCurrentIndexPaths containsObject:indexPath]) {
// We might be looking at an indexPath that was previously in-range, but now we need to clear it.
// In that case we'll just set it back to MeasureLayout. Only set Display | FetchData if in allCurrentIndexPaths.
interfaceState |= ASInterfaceStateDisplay;
interfaceState |= ASInterfaceStateFetchData;
}
}
NSInteger section = indexPath.section;
NSInteger row = indexPath.row;
if (section >= 0 && row >= 0 && section < numberOfSections) {
if (section != currentSectionIndex) {
// Often we'll be dealing with indexPaths in the same section, but the set isn't sorted and we may even bounce
// between the same ones. Still, this saves dozens of method calls to access the inner array and count.
currentSectionNodes = [allNodes objectAtIndex:section];
numberOfNodesInSection = [currentSectionNodes count];
currentSectionIndex = section;
}
if (row < numberOfNodesInSection) {
ASDisplayNode *node = [currentSectionNodes objectAtIndex:row];
ASDisplayNodeAssert(node.hierarchyState & ASHierarchyStateRangeManaged, @"All nodes reaching this point should be range-managed, or interfaceState may be incorrectly reset.");
// Skip the many method calls of the recursive operation if the top level cell node already has the right interfaceState.
if (node.interfaceState != interfaceState) {
#if RangeControllerLoggingEnabled
[modifiedIndexPaths addObject:indexPath];
#endif
[node recursivelySetInterfaceState:interfaceState];
}
}
}
}
if (_didRegisterForNotifications) {
_pendingDisplayNodesTimestamp = CFAbsoluteTimeGetCurrent();
}
_rangeIsValid = YES;
_queuedRangeUpdate = NO;
#if RangeControllerLoggingEnabled
NSSet *visibleNodePathsSet = [NSSet setWithArray:visibleNodePaths];
BOOL setsAreEqual = [visibleIndexPaths isEqualToSet:visibleNodePathsSet];
NSLog(@"visible sets are equal: %d", setsAreEqual);
if (!setsAreEqual) {
NSLog(@"standard: %@", visibleIndexPaths);
NSLog(@"custom: %@", visibleNodePathsSet);
}
[modifiedIndexPaths sortUsingSelector:@selector(compare:)];
for (NSIndexPath *indexPath in modifiedIndexPaths) {
ASDisplayNode *node = [_dataSource rangeController:self nodeAtIndexPath:indexPath];
ASInterfaceState interfaceState = node.interfaceState;
BOOL inVisible = ASInterfaceStateIncludesVisible(interfaceState);
BOOL inDisplay = ASInterfaceStateIncludesDisplay(interfaceState);
BOOL inFetchData = ASInterfaceStateIncludesFetchData(interfaceState);
NSLog(@"indexPath %@, Visible: %d, Display: %d, FetchData: %d", indexPath, inVisible, inDisplay, inFetchData);
}
#endif
}
#pragma mark - Notification observers
- (void)registerForNotificationsForInterfaceStateIfNeeded:(ASInterfaceState)interfaceState
{
if (!_didRegisterForNotifications) {
ASLayoutRangeMode nextRangeMode = [ASRangeControllerBeta rangeModeForInterfaceState:interfaceState
currentRangeMode:_currentRangeMode];
if (_currentRangeMode != nextRangeMode) {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(scheduledNodesDidDisplay:)
name:ASRenderingEngineDidDisplayScheduledNodesNotification
object:nil];
_didRegisterForNotifications = YES;
}
}
}
- (void)scheduledNodesDidDisplay:(NSNotification *)notification
{
CFAbsoluteTime notificationTimestamp = ((NSNumber *)[notification.userInfo objectForKey:ASRenderingEngineDidDisplayNodesScheduledBeforeTimestamp]).doubleValue;
if (_pendingDisplayNodesTimestamp < notificationTimestamp) {
// The rendering engine has processed all the nodes this range controller scheduled. Let's schedule a range update
[[NSNotificationCenter defaultCenter] removeObserver:self name:ASRenderingEngineDidDisplayScheduledNodesNotification object:nil];
_didRegisterForNotifications = NO;
[self scheduleRangeUpdate];
}
}
#pragma mark - Cell node view handling
- (void)configureContentView:(UIView *)contentView forCellNode:(ASCellNode *)node
{
ASDisplayNodeAssertMainThread();
ASDisplayNodeAssert(node, @"Cannot move a nil node to a view");
ASDisplayNodeAssert(contentView, @"Cannot move a node to a non-existent view");
if (node.view.superview == contentView) {
// this content view is already correctly configured
return;
}
// clean the content view
for (UIView *view in contentView.subviews) {
[view removeFromSuperview];
}
[contentView addSubview:node.view];
}
#pragma mark - ASDataControllerDelegete
- (void)dataControllerBeginUpdates:(ASDataController *)dataController
{
ASPerformBlockOnMainThread(^{
[_delegate didBeginUpdatesInRangeController:self];
});
}
- (void)dataController:(ASDataController *)dataController endUpdatesAnimated:(BOOL)animated completion:(void (^)(BOOL))completion
{
ASPerformBlockOnMainThread(^{
[_delegate rangeController:self didEndUpdatesAnimated:animated completion:completion];
});
}
- (void)dataController:(ASDataController *)dataController didInsertNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
{
ASDisplayNodeAssert(nodes.count == indexPaths.count, @"Invalid index path");
ASPerformBlockOnMainThread(^{
_rangeIsValid = NO;
[_delegate rangeController:self didInsertNodes:nodes atIndexPaths:indexPaths withAnimationOptions:animationOptions];
});
}
- (void)dataController:(ASDataController *)dataController didDeleteNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
{
ASPerformBlockOnMainThread(^{
_rangeIsValid = NO;
[_delegate rangeController:self didDeleteNodes:nodes atIndexPaths:indexPaths withAnimationOptions:animationOptions];
});
}
- (void)dataController:(ASDataController *)dataController didInsertSections:(NSArray *)sections atIndexSet:(NSIndexSet *)indexSet withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
{
ASDisplayNodeAssert(sections.count == indexSet.count, @"Invalid sections");
ASPerformBlockOnMainThread(^{
_rangeIsValid = NO;
[_delegate rangeController:self didInsertSectionsAtIndexSet:indexSet withAnimationOptions:animationOptions];
});
}
- (void)dataController:(ASDataController *)dataController didDeleteSectionsAtIndexSet:(NSIndexSet *)indexSet withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
{
ASPerformBlockOnMainThread(^{
_rangeIsValid = NO;
[_delegate rangeController:self didDeleteSectionsAtIndexSet:indexSet withAnimationOptions:animationOptions];
});
}
@end

View File

@ -1,26 +0,0 @@
/* 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>
NS_ASSUME_NONNULL_BEGIN
@class ASDisplayNode;
@protocol ASRangeHandler <NSObject>
@required
- (void)node:(ASDisplayNode *)node enteredRangeOfType:(ASLayoutRangeType)rangeType;
- (void)node:(ASDisplayNode *)node exitedRangeOfType:(ASLayoutRangeType)rangeType;
@end
NS_ASSUME_NONNULL_END

View File

@ -1,19 +0,0 @@
/* 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/ASRangeHandler.h>
NS_ASSUME_NONNULL_BEGIN
@interface ASRangeHandlerPreload : NSObject <ASRangeHandler>
@end
NS_ASSUME_NONNULL_END

View File

@ -1,27 +0,0 @@
/* 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 "ASRangeHandlerPreload.h"
#import "ASDisplayNode.h"
#import "ASDisplayNode+FrameworkPrivate.h"
@implementation ASRangeHandlerPreload
- (void)node:(ASDisplayNode *)node enteredRangeOfType:(ASLayoutRangeType)rangeType
{
ASDisplayNodeAssert(rangeType == ASLayoutRangeTypeFetchData, @"Preload delegate should not handle other ranges");
[node enterInterfaceState:ASInterfaceStateFetchData];
}
- (void)node:(ASDisplayNode *)node exitedRangeOfType:(ASLayoutRangeType)rangeType
{
ASDisplayNodeAssert(rangeType == ASLayoutRangeTypeFetchData, @"Preload delegate should not handle other ranges");
[node exitInterfaceState:ASInterfaceStateFetchData];
}
@end

View File

@ -1,19 +0,0 @@
/* 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/ASRangeHandler.h>
NS_ASSUME_NONNULL_BEGIN
@interface ASRangeHandlerRender : NSObject <ASRangeHandler>
@end
NS_ASSUME_NONNULL_END

View File

@ -1,128 +0,0 @@
/* 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 "ASRangeHandlerRender.h"
#import "ASDisplayNode.h"
#import "ASDisplayNode+Subclasses.h"
#import "ASDisplayNode+FrameworkPrivate.h"
#import "ASDisplayNode+Beta.h"
@interface ASRangeHandlerRender ()
@property (nonatomic,readonly) UIWindow *workingWindow;
@end
@implementation ASRangeHandlerRender
@synthesize workingWindow = _workingWindow;
- (UIWindow *)workingWindow
{
ASDisplayNodeAssertMainThread();
// we add nodes' views to this invisible window to start async rendering
// TODO: Replace this with directly triggering display https://github.com/facebook/AsyncDisplayKit/issues/315
// Update: Latest attempt is at https://github.com/facebook/AsyncDisplayKit/pull/828
if (!_workingWindow && ![ASDisplayNode shouldUseNewRenderingRange]) {
_workingWindow = [[UIWindow alloc] initWithFrame:CGRectZero];
_workingWindow.windowLevel = UIWindowLevelNormal - 1000;
_workingWindow.userInteractionEnabled = NO;
_workingWindow.hidden = YES;
_workingWindow.alpha = 0.0;
}
return _workingWindow;
}
- (void)dealloc
{
if (![ASDisplayNode shouldUseNewRenderingRange]) {
for (CALayer *layer in [self.workingWindow.layer.sublayers copy]) {
ASDisplayNode *node = layer.asyncdisplaykit_node;
[self node:node exitedRangeOfType:ASLayoutRangeTypeDisplay];
}
}
}
- (void)node:(ASDisplayNode *)node enteredRangeOfType:(ASLayoutRangeType)rangeType
{
ASDisplayNodeAssertMainThread();
ASDisplayNodeAssert(rangeType == ASLayoutRangeTypeDisplay, @"Render delegate should not handle other ranges");
// If a node had previously been onscreen but now is only in the working range,
// ensure its view is not orphaned in a UITableViewCell in the reuse pool.
if (![node isLayerBacked] && node.view.superview) {
[node.view removeFromSuperview];
}
// The node un-suspends display.
[node enterInterfaceState:ASInterfaceStateDisplay];
// ASDisplayNodeAssert(![ASDisplayNode shouldUseNewRenderingRange], @"It should no longer be possible to reach this point with the new display range enabled");
if ([ASDisplayNode shouldUseNewRenderingRange]) {
[node recursivelyEnsureDisplaySynchronously:NO];
} else {
// Add the node's layer to an off-screen window to trigger display and mark its contents as non-volatile.
// Use the layer directly to avoid the substantial overhead of UIView heirarchy manipulations.
// Any view-backed nodes will still create their views in order to assemble the layer heirarchy, and they will
// also assemble a view subtree for the node, but we avoid the much more significant expense triggered by a view
// being added or removed from an onscreen window (responder chain setup, will/DidMoveToWindow: recursive calls, etc)
[[[self workingWindow] layer] addSublayer:node.layer];
}
}
- (void)node:(ASDisplayNode *)node exitedRangeOfType:(ASLayoutRangeType)rangeType
{
ASDisplayNodeAssertMainThread();
ASDisplayNodeAssert(rangeType == ASLayoutRangeTypeDisplay, @"Render delegate should not handle other ranges");
// This code is tricky. There are several possible states a node can be in when it reaches this point.
// 1. Layer-backed vs view-backed nodes. AS of this writing, only ASCellNodes arrive here, which are always view-backed —
// but we maintain correctness for all ASDisplayNodes, including layer-backed ones.
// (Note: it would not make sense to pass in a subnode of a rasterized node here, so that is unsupported).
// 2. The node's layer may have been added to the workingWindow previously, or it may have never been added, such as if rangeTuningParameter's leading value is 0.
// 3. The node's layer may not be present in the workingWindow, even if it was previously added.
// This is a common case, as once the node is added to an active cell contentsView (e.g. visible), it is automatically removed from the workingWindow.
// The system does this when addSublayer is called, even if removeFromSuperlayer is never explicitly called.
// 4. Lastly and most unusually, it is possible for a node to be offscreen, completely outside the heirarchy, and yet considered within the working range.
// This happens if the UITableViewCell is reused after scrolling offscreen. Because the node has already been given the opportunity to display, we do not
// proactively re-host it within the workingWindow (improving efficiency). Some time later, it may fall outside the working range, in which case calling
// -recursivelyClearContents is critical. If the user scrolls back and it is re-hosted in a UITableViewCell, the content will still exist as it is not cleared
// by simply being removed from the cell. The code that usually triggers this condition is the -removeFromSuperview in -[ASRangeController configureContentView:forCellNode:].
// Condition #4 is suboptimal in some cases, as it is conceivable that memory warnings could trigger clearing content that is inside the working range. However, enforcing the
// preservation of this content could result in the app being killed, which is not likely preferable over briefly seeing placeholders in the event the user scrolls backwards.
// Nonetheless, future changes to the implementation will likely eliminate this behavior to simplify debugging and extensibility of working range functionality.
// The node calls clearCurrentContents and suspends display
[node exitInterfaceState:ASInterfaceStateDisplay];
// ASDisplayNodeAssert(![ASDisplayNode shouldUseNewRenderingRange], @"It should no longer be possible to reach this point with the new display range enabled");
if ([ASDisplayNode shouldUseNewRenderingRange]) {
if (![node isLayerBacked]) {
[node.view removeFromSuperview];
} else {
[node.layer removeFromSuperlayer];
}
} else {
if (node.layer.superlayer != [[self workingWindow] layer]) {
// In this case, the node has previously passed through the working range (or it is zero), and it has now fallen outside the working range.
if (![node isLayerBacked]) {
// If the node is view-backed, we need to make sure to remove the view (which is now present in the containing cell contentsView).
// Layer-backed nodes will be fully handled by the unconditional removal below.
[node.view removeFromSuperview];
}
}
// At this point, the node's layer may validly be present either in the workingWindow, or in the contentsView of a cell.
[node.layer removeFromSuperlayer];
}
}
@end

View File

@ -1,15 +0,0 @@
/* 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/ASRangeHandler.h>
@interface ASRangeHandlerVisible : NSObject <ASRangeHandler>
@end

View File

@ -1,25 +0,0 @@
/* 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 "ASRangeHandlerVisible.h"
#import "ASDisplayNode.h"
#import "ASDisplayNode+FrameworkPrivate.h"
@implementation ASRangeHandlerVisible
- (void)node:(ASDisplayNode *)node enteredRangeOfType:(ASLayoutRangeType)rangeType
{
[node enterInterfaceState:ASInterfaceStateVisible];
}
- (void)node:(ASDisplayNode *)node exitedRangeOfType:(ASLayoutRangeType)rangeType
{
[node exitInterfaceState:ASInterfaceStateVisible];
}
@end

View File

@ -290,13 +290,11 @@
_messageToViewOrLayer(setNeedsDisplay);
if ([ASDisplayNode shouldUseNewRenderingRange]) {
BOOL nowDisplay = ASInterfaceStateIncludesDisplay(_interfaceState);
// FIXME: This should not need to recursively display, so create a non-recursive variant.
// The semantics of setNeedsDisplay (as defined by CALayer behavior) are not recursive.
if (_layer && !_flags.synchronous && nowDisplay && [self __implementsDisplay]) {
[ASDisplayNode scheduleNodeForRecursiveDisplay:self];
}
BOOL nowDisplay = ASInterfaceStateIncludesDisplay(_interfaceState);
// FIXME: This should not need to recursively display, so create a non-recursive variant.
// The semantics of setNeedsDisplay (as defined by CALayer behavior) are not recursive.
if (_layer && !_flags.synchronous && nowDisplay && [self __implementsDisplay]) {
[ASDisplayNode scheduleNodeForRecursiveDisplay:self];
}
}
}

View File

@ -14,7 +14,6 @@
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[ASDisplayNode setShouldUseNewRenderingRange:YES];
return YES;
}

View File

@ -20,8 +20,6 @@
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[ASDisplayNode setShouldUseNewRenderingRange:YES];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
self.window.rootViewController = [[UINavigationController alloc] init];

View File

@ -19,9 +19,7 @@
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[ASDisplayNode setShouldUseNewRenderingRange:YES];
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
self.window.rootViewController = [[UINavigationController alloc] initWithRootViewController:[[ViewController alloc] init]];