mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-23 22:55:00 +00:00
Merge branch 'master' into pr/664
This commit is contained in:
Binary file not shown.
@@ -128,7 +128,7 @@
|
|||||||
242995D31B29743C00090100 /* ASBasicImageDownloaderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 242995D21B29743C00090100 /* ASBasicImageDownloaderTests.m */; };
|
242995D31B29743C00090100 /* ASBasicImageDownloaderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 242995D21B29743C00090100 /* ASBasicImageDownloaderTests.m */; };
|
||||||
251B8EF71BBB3D690087C538 /* ASCollectionDataController.h in Headers */ = {isa = PBXBuildFile; fileRef = 251B8EF21BBB3D690087C538 /* ASCollectionDataController.h */; };
|
251B8EF71BBB3D690087C538 /* ASCollectionDataController.h in Headers */ = {isa = PBXBuildFile; fileRef = 251B8EF21BBB3D690087C538 /* ASCollectionDataController.h */; };
|
||||||
251B8EF81BBB3D690087C538 /* ASCollectionDataController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 251B8EF31BBB3D690087C538 /* ASCollectionDataController.mm */; };
|
251B8EF81BBB3D690087C538 /* ASCollectionDataController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 251B8EF31BBB3D690087C538 /* ASCollectionDataController.mm */; };
|
||||||
251B8EF91BBB3D690087C538 /* ASCollectionViewFlowLayoutInspector.h in Headers */ = {isa = PBXBuildFile; fileRef = 251B8EF41BBB3D690087C538 /* ASCollectionViewFlowLayoutInspector.h */; };
|
251B8EF91BBB3D690087C538 /* ASCollectionViewFlowLayoutInspector.h in Headers */ = {isa = PBXBuildFile; fileRef = 251B8EF41BBB3D690087C538 /* ASCollectionViewFlowLayoutInspector.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
251B8EFA1BBB3D690087C538 /* ASCollectionViewFlowLayoutInspector.m in Sources */ = {isa = PBXBuildFile; fileRef = 251B8EF51BBB3D690087C538 /* ASCollectionViewFlowLayoutInspector.m */; };
|
251B8EFA1BBB3D690087C538 /* ASCollectionViewFlowLayoutInspector.m in Sources */ = {isa = PBXBuildFile; fileRef = 251B8EF51BBB3D690087C538 /* ASCollectionViewFlowLayoutInspector.m */; };
|
||||||
251B8EFB1BBB3D690087C538 /* ASDataController+Subclasses.h in Headers */ = {isa = PBXBuildFile; fileRef = 251B8EF61BBB3D690087C538 /* ASDataController+Subclasses.h */; };
|
251B8EFB1BBB3D690087C538 /* ASDataController+Subclasses.h in Headers */ = {isa = PBXBuildFile; fileRef = 251B8EF61BBB3D690087C538 /* ASDataController+Subclasses.h */; };
|
||||||
2538B6F31BC5D2A2003CA0B4 /* ASCollectionViewFlowLayoutInspectorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2538B6F21BC5D2A2003CA0B4 /* ASCollectionViewFlowLayoutInspectorTests.m */; };
|
2538B6F31BC5D2A2003CA0B4 /* ASCollectionViewFlowLayoutInspectorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2538B6F21BC5D2A2003CA0B4 /* ASCollectionViewFlowLayoutInspectorTests.m */; };
|
||||||
@@ -242,7 +242,7 @@
|
|||||||
34EFC7771B701D2D00AD841F /* ASStackUnpositionedLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = ACF6ED491B17847A00DA7C62 /* ASStackUnpositionedLayout.h */; };
|
34EFC7771B701D2D00AD841F /* ASStackUnpositionedLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = ACF6ED491B17847A00DA7C62 /* ASStackUnpositionedLayout.h */; };
|
||||||
34EFC7781B701D3100AD841F /* ASStackUnpositionedLayout.mm in Sources */ = {isa = PBXBuildFile; fileRef = ACF6ED4A1B17847A00DA7C62 /* ASStackUnpositionedLayout.mm */; };
|
34EFC7781B701D3100AD841F /* ASStackUnpositionedLayout.mm in Sources */ = {isa = PBXBuildFile; fileRef = ACF6ED4A1B17847A00DA7C62 /* ASStackUnpositionedLayout.mm */; };
|
||||||
34EFC7791B701D3600AD841F /* ASLayoutSpecUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = ACF6ED451B17847A00DA7C62 /* ASLayoutSpecUtilities.h */; };
|
34EFC7791B701D3600AD841F /* ASLayoutSpecUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = ACF6ED451B17847A00DA7C62 /* ASLayoutSpecUtilities.h */; };
|
||||||
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 */; };
|
||||||
430E7C8F1B4C23F100697A4C /* ASIndexPath.h in Headers */ = {isa = PBXBuildFile; fileRef = 430E7C8D1B4C23F100697A4C /* ASIndexPath.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
430E7C8F1B4C23F100697A4C /* ASIndexPath.h in Headers */ = {isa = PBXBuildFile; fileRef = 430E7C8D1B4C23F100697A4C /* ASIndexPath.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
430E7C901B4C23F100697A4C /* ASIndexPath.h in Headers */ = {isa = PBXBuildFile; fileRef = 430E7C8D1B4C23F100697A4C /* ASIndexPath.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
430E7C901B4C23F100697A4C /* ASIndexPath.h in Headers */ = {isa = PBXBuildFile; fileRef = 430E7C8D1B4C23F100697A4C /* ASIndexPath.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
430E7C911B4C23F100697A4C /* ASIndexPath.m in Sources */ = {isa = PBXBuildFile; fileRef = 430E7C8E1B4C23F100697A4C /* ASIndexPath.m */; };
|
430E7C911B4C23F100697A4C /* ASIndexPath.m in Sources */ = {isa = PBXBuildFile; fileRef = 430E7C8E1B4C23F100697A4C /* ASIndexPath.m */; };
|
||||||
@@ -458,8 +458,13 @@
|
|||||||
D785F6621A74327E00291744 /* ASScrollNode.h in Headers */ = {isa = PBXBuildFile; fileRef = D785F6601A74327E00291744 /* ASScrollNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
D785F6621A74327E00291744 /* ASScrollNode.h in Headers */ = {isa = PBXBuildFile; fileRef = D785F6601A74327E00291744 /* ASScrollNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
D785F6631A74327E00291744 /* ASScrollNode.m in Sources */ = {isa = PBXBuildFile; fileRef = D785F6611A74327E00291744 /* ASScrollNode.m */; };
|
D785F6631A74327E00291744 /* ASScrollNode.m in Sources */ = {isa = PBXBuildFile; fileRef = D785F6611A74327E00291744 /* ASScrollNode.m */; };
|
||||||
DB7121BCD50849C498C886FB /* libPods-AsyncDisplayKitTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = EFA731F0396842FF8AB635EE /* libPods-AsyncDisplayKitTests.a */; };
|
DB7121BCD50849C498C886FB /* libPods-AsyncDisplayKitTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = EFA731F0396842FF8AB635EE /* libPods-AsyncDisplayKitTests.a */; };
|
||||||
|
DE040EF91C2B40AC004692FF /* ASCollectionViewFlowLayoutInspector.h in Headers */ = {isa = PBXBuildFile; fileRef = 251B8EF41BBB3D690087C538 /* ASCollectionViewFlowLayoutInspector.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
DE6EA3221C14000600183B10 /* ASDisplayNode+FrameworkPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = DE6EA3211C14000600183B10 /* ASDisplayNode+FrameworkPrivate.h */; };
|
DE6EA3221C14000600183B10 /* ASDisplayNode+FrameworkPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = DE6EA3211C14000600183B10 /* ASDisplayNode+FrameworkPrivate.h */; };
|
||||||
DE6EA3231C14000600183B10 /* ASDisplayNode+FrameworkPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = DE6EA3211C14000600183B10 /* ASDisplayNode+FrameworkPrivate.h */; };
|
DE6EA3231C14000600183B10 /* ASDisplayNode+FrameworkPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = DE6EA3211C14000600183B10 /* ASDisplayNode+FrameworkPrivate.h */; };
|
||||||
|
DE8BEAC11C2DF3FC00D57C12 /* ASDelegateProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = DE8BEABF1C2DF3FC00D57C12 /* ASDelegateProxy.h */; };
|
||||||
|
DE8BEAC21C2DF3FC00D57C12 /* ASDelegateProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = DE8BEABF1C2DF3FC00D57C12 /* ASDelegateProxy.h */; };
|
||||||
|
DE8BEAC31C2DF3FC00D57C12 /* ASDelegateProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = DE8BEAC01C2DF3FC00D57C12 /* ASDelegateProxy.m */; };
|
||||||
|
DE8BEAC41C2DF3FC00D57C12 /* ASDelegateProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = DE8BEAC01C2DF3FC00D57C12 /* ASDelegateProxy.m */; };
|
||||||
DECBD6E71BE56E1900CF4905 /* ASButtonNode.h in Headers */ = {isa = PBXBuildFile; fileRef = DECBD6E51BE56E1900CF4905 /* ASButtonNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
DECBD6E71BE56E1900CF4905 /* ASButtonNode.h in Headers */ = {isa = PBXBuildFile; fileRef = DECBD6E51BE56E1900CF4905 /* ASButtonNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
DECBD6E81BE56E1900CF4905 /* ASButtonNode.h in Headers */ = {isa = PBXBuildFile; fileRef = DECBD6E51BE56E1900CF4905 /* ASButtonNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
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 */; };
|
DECBD6E91BE56E1900CF4905 /* ASButtonNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = DECBD6E61BE56E1900CF4905 /* ASButtonNode.mm */; };
|
||||||
@@ -753,6 +758,8 @@
|
|||||||
D785F6601A74327E00291744 /* ASScrollNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASScrollNode.h; sourceTree = "<group>"; };
|
D785F6601A74327E00291744 /* ASScrollNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASScrollNode.h; sourceTree = "<group>"; };
|
||||||
D785F6611A74327E00291744 /* ASScrollNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASScrollNode.m; sourceTree = "<group>"; };
|
D785F6611A74327E00291744 /* ASScrollNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASScrollNode.m; sourceTree = "<group>"; };
|
||||||
DE6EA3211C14000600183B10 /* ASDisplayNode+FrameworkPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ASDisplayNode+FrameworkPrivate.h"; sourceTree = "<group>"; };
|
DE6EA3211C14000600183B10 /* ASDisplayNode+FrameworkPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ASDisplayNode+FrameworkPrivate.h"; sourceTree = "<group>"; };
|
||||||
|
DE8BEABF1C2DF3FC00D57C12 /* ASDelegateProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASDelegateProxy.h; sourceTree = "<group>"; };
|
||||||
|
DE8BEAC01C2DF3FC00D57C12 /* ASDelegateProxy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASDelegateProxy.m; sourceTree = "<group>"; };
|
||||||
DECBD6E51BE56E1900CF4905 /* ASButtonNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASButtonNode.h; 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>"; };
|
DECBD6E61BE56E1900CF4905 /* ASButtonNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASButtonNode.mm; sourceTree = "<group>"; };
|
||||||
EFA731F0396842FF8AB635EE /* libPods-AsyncDisplayKitTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-AsyncDisplayKitTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
EFA731F0396842FF8AB635EE /* libPods-AsyncDisplayKitTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-AsyncDisplayKitTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
@@ -1148,6 +1155,8 @@
|
|||||||
25B171EA1C12242700508A7A /* Data Controller */ = {
|
25B171EA1C12242700508A7A /* Data Controller */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
DE8BEABF1C2DF3FC00D57C12 /* ASDelegateProxy.h */,
|
||||||
|
DE8BEAC01C2DF3FC00D57C12 /* ASDelegateProxy.m */,
|
||||||
251B8EF21BBB3D690087C538 /* ASCollectionDataController.h */,
|
251B8EF21BBB3D690087C538 /* ASCollectionDataController.h */,
|
||||||
251B8EF31BBB3D690087C538 /* ASCollectionDataController.mm */,
|
251B8EF31BBB3D690087C538 /* ASCollectionDataController.mm */,
|
||||||
464052191A3F83C40061C0BA /* ASDataController.h */,
|
464052191A3F83C40061C0BA /* ASDataController.h */,
|
||||||
@@ -1263,6 +1272,7 @@
|
|||||||
18C2ED7E1B9B7DE800F627B3 /* ASCollectionNode.h in Headers */,
|
18C2ED7E1B9B7DE800F627B3 /* ASCollectionNode.h in Headers */,
|
||||||
257754C01BEE458E00737CA5 /* ASTextNodeWordKerner.h in Headers */,
|
257754C01BEE458E00737CA5 /* ASTextNodeWordKerner.h in Headers */,
|
||||||
AC3C4A511A1139C100143C57 /* ASCollectionView.h in Headers */,
|
AC3C4A511A1139C100143C57 /* ASCollectionView.h in Headers */,
|
||||||
|
DE8BEAC11C2DF3FC00D57C12 /* ASDelegateProxy.h in Headers */,
|
||||||
205F0E1D1B373A2C007741D0 /* ASCollectionViewLayoutController.h in Headers */,
|
205F0E1D1B373A2C007741D0 /* ASCollectionViewLayoutController.h in Headers */,
|
||||||
AC3C4A541A113EEC00143C57 /* ASCollectionViewProtocols.h in Headers */,
|
AC3C4A541A113EEC00143C57 /* ASCollectionViewProtocols.h in Headers */,
|
||||||
058D0A49195D05CB00B7D73C /* ASControlNode+Subclasses.h in Headers */,
|
058D0A49195D05CB00B7D73C /* ASControlNode+Subclasses.h in Headers */,
|
||||||
@@ -1431,6 +1441,7 @@
|
|||||||
34EFC7791B701D3600AD841F /* ASLayoutSpecUtilities.h in Headers */,
|
34EFC7791B701D3600AD841F /* ASLayoutSpecUtilities.h in Headers */,
|
||||||
B350625C1B010F070018CF92 /* ASLog.h in Headers */,
|
B350625C1B010F070018CF92 /* ASLog.h in Headers */,
|
||||||
0442850E1BAA64EC00D16268 /* ASMultidimensionalArrayUtils.h in Headers */,
|
0442850E1BAA64EC00D16268 /* ASMultidimensionalArrayUtils.h in Headers */,
|
||||||
|
DE8BEAC21C2DF3FC00D57C12 /* ASDelegateProxy.h in Headers */,
|
||||||
B35062041B010EFD0018CF92 /* ASMultiplexImageNode.h in Headers */,
|
B35062041B010EFD0018CF92 /* ASMultiplexImageNode.h in Headers */,
|
||||||
DECBD6E81BE56E1900CF4905 /* ASButtonNode.h in Headers */,
|
DECBD6E81BE56E1900CF4905 /* ASButtonNode.h in Headers */,
|
||||||
B35062241B010EFD0018CF92 /* ASMutableAttributedStringBuilder.h in Headers */,
|
B35062241B010EFD0018CF92 /* ASMutableAttributedStringBuilder.h in Headers */,
|
||||||
@@ -1451,6 +1462,7 @@
|
|||||||
B35062551B010EFD0018CF92 /* ASSentinel.h in Headers */,
|
B35062551B010EFD0018CF92 /* ASSentinel.h in Headers */,
|
||||||
9C8221961BA237B80037F19A /* ASStackBaselinePositionedLayout.h in Headers */,
|
9C8221961BA237B80037F19A /* ASStackBaselinePositionedLayout.h in Headers */,
|
||||||
9C49C3701B853961000B0DD5 /* ASStackLayoutable.h in Headers */,
|
9C49C3701B853961000B0DD5 /* ASStackLayoutable.h in Headers */,
|
||||||
|
DE040EF91C2B40AC004692FF /* ASCollectionViewFlowLayoutInspector.h in Headers */,
|
||||||
34EFC7701B701CFA00AD841F /* ASStackLayoutDefines.h in Headers */,
|
34EFC7701B701CFA00AD841F /* ASStackLayoutDefines.h in Headers */,
|
||||||
254C6B7B1BF94DF4003EC431 /* ASTextKitRenderer+Positioning.h in Headers */,
|
254C6B7B1BF94DF4003EC431 /* ASTextKitRenderer+Positioning.h in Headers */,
|
||||||
CC7FD9E21BB603FF005CCB2B /* ASPhotosFrameworkImageRequest.h in Headers */,
|
CC7FD9E21BB603FF005CCB2B /* ASPhotosFrameworkImageRequest.h in Headers */,
|
||||||
@@ -1523,7 +1535,6 @@
|
|||||||
058D09B9195D04C000B7D73C /* Frameworks */,
|
058D09B9195D04C000B7D73C /* Frameworks */,
|
||||||
058D09BA195D04C000B7D73C /* Resources */,
|
058D09BA195D04C000B7D73C /* Resources */,
|
||||||
3B9D88CDF51B429C8409E4B6 /* Copy Pods Resources */,
|
3B9D88CDF51B429C8409E4B6 /* Copy Pods Resources */,
|
||||||
1B86F48711505F91D5FEF571 /* Embed Pods Frameworks */,
|
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
@@ -1623,21 +1634,6 @@
|
|||||||
/* End PBXResourcesBuildPhase section */
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXShellScriptBuildPhase section */
|
/* Begin PBXShellScriptBuildPhase section */
|
||||||
1B86F48711505F91D5FEF571 /* Embed Pods Frameworks */ = {
|
|
||||||
isa = PBXShellScriptBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
inputPaths = (
|
|
||||||
);
|
|
||||||
name = "Embed Pods Frameworks";
|
|
||||||
outputPaths = (
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
shellPath = /bin/sh;
|
|
||||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-AsyncDisplayKitTests/Pods-AsyncDisplayKitTests-frameworks.sh\"\n";
|
|
||||||
showEnvVarsInLog = 0;
|
|
||||||
};
|
|
||||||
2E61B6A0DB0F436A9DDBE86F /* Check Pods Manifest.lock */ = {
|
2E61B6A0DB0F436A9DDBE86F /* Check Pods Manifest.lock */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
@@ -1701,6 +1697,7 @@
|
|||||||
0549634A1A1EA066000F8E56 /* ASBasicImageDownloader.mm in Sources */,
|
0549634A1A1EA066000F8E56 /* ASBasicImageDownloader.mm in Sources */,
|
||||||
299DA1AA1A828D2900162D41 /* ASBatchContext.mm in Sources */,
|
299DA1AA1A828D2900162D41 /* ASBatchContext.mm in Sources */,
|
||||||
AC6456091B0A335000CF11B8 /* ASCellNode.m in Sources */,
|
AC6456091B0A335000CF11B8 /* ASCellNode.m in Sources */,
|
||||||
|
DE8BEAC31C2DF3FC00D57C12 /* ASDelegateProxy.m in Sources */,
|
||||||
ACF6ED1D1B17843500DA7C62 /* ASCenterLayoutSpec.mm in Sources */,
|
ACF6ED1D1B17843500DA7C62 /* ASCenterLayoutSpec.mm in Sources */,
|
||||||
18C2ED801B9B7DE800F627B3 /* ASCollectionNode.m in Sources */,
|
18C2ED801B9B7DE800F627B3 /* ASCollectionNode.m in Sources */,
|
||||||
92DD2FE41BF4B97E0074C9DD /* ASMapNode.mm in Sources */,
|
92DD2FE41BF4B97E0074C9DD /* ASMapNode.mm in Sources */,
|
||||||
@@ -1830,6 +1827,7 @@
|
|||||||
509E68621B3AEDA5009B9150 /* ASAbstractLayoutController.mm in Sources */,
|
509E68621B3AEDA5009B9150 /* ASAbstractLayoutController.mm in Sources */,
|
||||||
254C6B861BF94F8A003EC431 /* ASTextKitContext.mm in Sources */,
|
254C6B861BF94F8A003EC431 /* ASTextKitContext.mm in Sources */,
|
||||||
34EFC7621B701CA400AD841F /* ASBackgroundLayoutSpec.mm in Sources */,
|
34EFC7621B701CA400AD841F /* ASBackgroundLayoutSpec.mm in Sources */,
|
||||||
|
DE8BEAC41C2DF3FC00D57C12 /* ASDelegateProxy.m in Sources */,
|
||||||
B35062141B010EFD0018CF92 /* ASBasicImageDownloader.mm in Sources */,
|
B35062141B010EFD0018CF92 /* ASBasicImageDownloader.mm in Sources */,
|
||||||
B35062161B010EFD0018CF92 /* ASBatchContext.mm in Sources */,
|
B35062161B010EFD0018CF92 /* ASBatchContext.mm in Sources */,
|
||||||
AC47D9421B3B891B00AAEE9D /* ASCellNode.m in Sources */,
|
AC47D9421B3B891B00AAEE9D /* ASCellNode.m in Sources */,
|
||||||
@@ -1936,6 +1934,7 @@
|
|||||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
GCC_INSTRUMENT_PROGRAM_FLOW_ARCS = NO;
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
"DEBUG=1",
|
"DEBUG=1",
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
@@ -1956,6 +1955,7 @@
|
|||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
COPY_PHASE_STRIP = NO;
|
COPY_PHASE_STRIP = NO;
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
GCC_INSTRUMENT_PROGRAM_FLOW_ARCS = NO;
|
||||||
INFOPLIST_FILE = AsyncDisplayKitTestHost/Info.plist;
|
INFOPLIST_FILE = AsyncDisplayKitTestHost/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||||
@@ -2043,6 +2043,7 @@
|
|||||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||||
DSTROOT = /tmp/AsyncDisplayKit.dst;
|
DSTROOT = /tmp/AsyncDisplayKit.dst;
|
||||||
GCC_INPUT_FILETYPE = automatic;
|
GCC_INPUT_FILETYPE = automatic;
|
||||||
|
GCC_INSTRUMENT_PROGRAM_FLOW_ARCS = NO;
|
||||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||||
GCC_PREFIX_HEADER = "AsyncDisplayKit/AsyncDisplayKit-Prefix.pch";
|
GCC_PREFIX_HEADER = "AsyncDisplayKit/AsyncDisplayKit-Prefix.pch";
|
||||||
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
||||||
@@ -2061,6 +2062,7 @@
|
|||||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||||
DSTROOT = /tmp/AsyncDisplayKit.dst;
|
DSTROOT = /tmp/AsyncDisplayKit.dst;
|
||||||
GCC_INPUT_FILETYPE = automatic;
|
GCC_INPUT_FILETYPE = automatic;
|
||||||
|
GCC_INSTRUMENT_PROGRAM_FLOW_ARCS = NO;
|
||||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||||
GCC_PREFIX_HEADER = "AsyncDisplayKit/AsyncDisplayKit-Prefix.pch";
|
GCC_PREFIX_HEADER = "AsyncDisplayKit/AsyncDisplayKit-Prefix.pch";
|
||||||
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
||||||
@@ -2083,6 +2085,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"$(DEVELOPER_FRAMEWORKS_DIR)",
|
"$(DEVELOPER_FRAMEWORKS_DIR)",
|
||||||
);
|
);
|
||||||
|
GCC_INSTRUMENT_PROGRAM_FLOW_ARCS = NO;
|
||||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||||
GCC_PREFIX_HEADER = "AsyncDisplayKit/AsyncDisplayKit-Prefix.pch";
|
GCC_PREFIX_HEADER = "AsyncDisplayKit/AsyncDisplayKit-Prefix.pch";
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
@@ -2110,6 +2113,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"$(DEVELOPER_FRAMEWORKS_DIR)",
|
"$(DEVELOPER_FRAMEWORKS_DIR)",
|
||||||
);
|
);
|
||||||
|
GCC_INSTRUMENT_PROGRAM_FLOW_ARCS = NO;
|
||||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||||
GCC_PREFIX_HEADER = "AsyncDisplayKit/AsyncDisplayKit-Prefix.pch";
|
GCC_PREFIX_HEADER = "AsyncDisplayKit/AsyncDisplayKit-Prefix.pch";
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
@@ -2138,6 +2142,7 @@
|
|||||||
DYLIB_CURRENT_VERSION = 1;
|
DYLIB_CURRENT_VERSION = 1;
|
||||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
GCC_INSTRUMENT_PROGRAM_FLOW_ARCS = NO;
|
||||||
GCC_NO_COMMON_BLOCKS = YES;
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
"DEBUG=1",
|
"DEBUG=1",
|
||||||
@@ -2170,6 +2175,7 @@
|
|||||||
DYLIB_CURRENT_VERSION = 1;
|
DYLIB_CURRENT_VERSION = 1;
|
||||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
GCC_INSTRUMENT_PROGRAM_FLOW_ARCS = NO;
|
||||||
GCC_NO_COMMON_BLOCKS = YES;
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
INFOPLIST_FILE = "$(SRCROOT)/AsyncDisplayKit-iOS/Info.plist";
|
INFOPLIST_FILE = "$(SRCROOT)/AsyncDisplayKit-iOS/Info.plist";
|
||||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||||
|
|||||||
@@ -31,6 +31,17 @@ typedef enum : NSUInteger {
|
|||||||
*/
|
*/
|
||||||
@property (nonatomic, assign) BOOL laysOutHorizontally;
|
@property (nonatomic, assign) BOOL laysOutHorizontally;
|
||||||
|
|
||||||
|
/** Horizontally align content (text or image).
|
||||||
|
Defaults to ASAlignmentMiddle.
|
||||||
|
*/
|
||||||
|
@property (nonatomic, assign) ASHorizontalAlignment contentHorizontalAlignment;
|
||||||
|
|
||||||
|
/** Vertically align content (text or image).
|
||||||
|
Defaults to ASAlignmentCenter.
|
||||||
|
*/
|
||||||
|
@property (nonatomic, assign) ASVerticalAlignment contentVerticalAlignment;
|
||||||
|
|
||||||
|
|
||||||
- (NSAttributedString *)attributedTitleForState:(ASButtonState)state;
|
- (NSAttributedString *)attributedTitleForState:(ASButtonState)state;
|
||||||
- (void)setAttributedTitle:(NSAttributedString *)title forState:(ASButtonState)state;
|
- (void)setAttributedTitle:(NSAttributedString *)title forState:(ASButtonState)state;
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,9 @@
|
|||||||
_titleNode = [[ASTextNode alloc] init];
|
_titleNode = [[ASTextNode alloc] init];
|
||||||
_imageNode = [[ASImageNode alloc] init];
|
_imageNode = [[ASImageNode alloc] init];
|
||||||
|
|
||||||
|
_contentHorizontalAlignment = ASAlignmentMiddle;
|
||||||
|
_contentVerticalAlignment = ASAlignmentCenter;
|
||||||
|
|
||||||
[self addSubnode:_titleNode];
|
[self addSubnode:_titleNode];
|
||||||
[self addSubnode:_imageNode];
|
[self addSubnode:_imageNode];
|
||||||
|
|
||||||
@@ -195,8 +198,8 @@
|
|||||||
ASStackLayoutSpec *stack = [[ASStackLayoutSpec alloc] init];
|
ASStackLayoutSpec *stack = [[ASStackLayoutSpec alloc] init];
|
||||||
stack.direction = self.laysOutHorizontally ? ASStackLayoutDirectionHorizontal : ASStackLayoutDirectionVertical;
|
stack.direction = self.laysOutHorizontally ? ASStackLayoutDirectionHorizontal : ASStackLayoutDirectionVertical;
|
||||||
stack.spacing = self.contentSpacing;
|
stack.spacing = self.contentSpacing;
|
||||||
stack.justifyContent = ASStackLayoutJustifyContentCenter;
|
stack.horizontalAlignment = _contentHorizontalAlignment;
|
||||||
stack.alignItems = ASStackLayoutAlignItemsCenter;
|
stack.verticalAlignment = _contentVerticalAlignment;
|
||||||
|
|
||||||
NSMutableArray *children = [[NSMutableArray alloc] initWithCapacity:2];
|
NSMutableArray *children = [[NSMutableArray alloc] initWithCapacity:2];
|
||||||
if (self.imageNode.image) {
|
if (self.imageNode.image) {
|
||||||
|
|||||||
@@ -16,7 +16,11 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
*/
|
*/
|
||||||
@interface ASCollectionNode : ASDisplayNode
|
@interface ASCollectionNode : ASDisplayNode
|
||||||
|
|
||||||
- (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout *)layout NS_DESIGNATED_INITIALIZER;
|
- (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout *)layout;
|
||||||
|
- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout;
|
||||||
|
|
||||||
|
@property (weak, nonatomic) id <ASCollectionDelegate> delegate;
|
||||||
|
@property (weak, nonatomic) id <ASCollectionDataSource> dataSource;
|
||||||
|
|
||||||
@property (nonatomic, readonly) ASCollectionView *view;
|
@property (nonatomic, readonly) ASCollectionView *view;
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,22 @@
|
|||||||
#import "ASCollectionNode.h"
|
#import "ASCollectionNode.h"
|
||||||
#import "ASDisplayNode+Subclasses.h"
|
#import "ASDisplayNode+Subclasses.h"
|
||||||
|
|
||||||
|
@interface _ASCollectionPendingState : NSObject
|
||||||
|
@property (weak, nonatomic) id <ASCollectionDelegate> delegate;
|
||||||
|
@property (weak, nonatomic) id <ASCollectionDataSource> dataSource;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation _ASCollectionPendingState
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface ASCollectionNode ()
|
||||||
|
@property (nonatomic) _ASCollectionPendingState *pendingState;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface ASCollectionView ()
|
||||||
|
- (instancetype)_initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout;
|
||||||
|
@end
|
||||||
|
|
||||||
@implementation ASCollectionNode
|
@implementation ASCollectionNode
|
||||||
|
|
||||||
- (instancetype)init
|
- (instancetype)init
|
||||||
@@ -21,17 +37,92 @@
|
|||||||
|
|
||||||
- (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout *)layout
|
- (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout *)layout
|
||||||
{
|
{
|
||||||
if (self = [super initWithViewBlock:^UIView *{ return [[ASCollectionView alloc] initWithCollectionViewLayout:layout]; }]) {
|
return [self initWithFrame:CGRectZero collectionViewLayout:layout];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout
|
||||||
|
{
|
||||||
|
ASDisplayNodeViewBlock collectionViewBlock = ^UIView *{
|
||||||
|
return [[ASCollectionView alloc] _initWithFrame:frame collectionViewLayout:layout];
|
||||||
|
};
|
||||||
|
|
||||||
|
if (self = [super initWithViewBlock:collectionViewBlock]) {
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)didLoad
|
||||||
|
{
|
||||||
|
[super didLoad];
|
||||||
|
|
||||||
|
if (_pendingState) {
|
||||||
|
_ASCollectionPendingState *pendingState = _pendingState;
|
||||||
|
self.pendingState = nil;
|
||||||
|
|
||||||
|
ASCollectionView *view = self.view;
|
||||||
|
view.asyncDelegate = pendingState.delegate;
|
||||||
|
view.asyncDataSource = pendingState.dataSource;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (_ASCollectionPendingState *)pendingState
|
||||||
|
{
|
||||||
|
if (!_pendingState && ![self isNodeLoaded]) {
|
||||||
|
self.pendingState = [[_ASCollectionPendingState alloc] init];
|
||||||
|
}
|
||||||
|
ASDisplayNodeAssert(![self isNodeLoaded] || !_pendingState, @"ASCollectionNode should not have a pendingState once it is loaded");
|
||||||
|
return _pendingState;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setDelegate:(id <ASCollectionDelegate>)delegate
|
||||||
|
{
|
||||||
|
if ([self pendingState]) {
|
||||||
|
_pendingState.delegate = delegate;
|
||||||
|
} else {
|
||||||
|
ASDisplayNodeAssert([self isNodeLoaded], @"ASCollectionNode should be loaded if pendingState doesn't exist");
|
||||||
|
self.view.asyncDelegate = delegate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id <ASCollectionDelegate>)delegate
|
||||||
|
{
|
||||||
|
if ([self pendingState]) {
|
||||||
|
return _pendingState.delegate;
|
||||||
|
} else {
|
||||||
|
return self.view.asyncDelegate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setDataSource:(id <ASCollectionDataSource>)dataSource
|
||||||
|
{
|
||||||
|
if ([self pendingState]) {
|
||||||
|
_pendingState.dataSource = dataSource;
|
||||||
|
} else {
|
||||||
|
ASDisplayNodeAssert([self isNodeLoaded], @"ASCollectionNode should be loaded if pendingState doesn't exist");
|
||||||
|
self.view.asyncDataSource = dataSource;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id <ASCollectionDataSource>)dataSource
|
||||||
|
{
|
||||||
|
if ([self pendingState]) {
|
||||||
|
return _pendingState.dataSource;
|
||||||
|
} else {
|
||||||
|
return self.view.asyncDataSource;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (ASCollectionView *)view
|
- (ASCollectionView *)view
|
||||||
{
|
{
|
||||||
return (ASCollectionView *)[super view];
|
return (ASCollectionView *)[super view];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)visibilityDidChange:(BOOL)isVisible
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
- (void)clearContents
|
- (void)clearContents
|
||||||
{
|
{
|
||||||
[super clearContents];
|
[super clearContents];
|
||||||
|
|||||||
@@ -12,11 +12,11 @@
|
|||||||
#import <AsyncDisplayKit/ASCollectionViewProtocols.h>
|
#import <AsyncDisplayKit/ASCollectionViewProtocols.h>
|
||||||
#import <AsyncDisplayKit/ASBaseDefines.h>
|
#import <AsyncDisplayKit/ASBaseDefines.h>
|
||||||
#import <AsyncDisplayKit/ASBatchContext.h>
|
#import <AsyncDisplayKit/ASBatchContext.h>
|
||||||
|
#import <AsyncDisplayKit/ASCollectionViewFlowLayoutInspector.h>
|
||||||
|
|
||||||
@class ASCellNode;
|
@class ASCellNode;
|
||||||
@protocol ASCollectionViewDataSource;
|
@protocol ASCollectionDataSource;
|
||||||
@protocol ASCollectionViewDelegate;
|
@protocol ASCollectionDelegate;
|
||||||
@protocol ASCollectionViewLayoutInspecting;
|
@protocol ASCollectionViewLayoutInspecting;
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
@@ -29,10 +29,16 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
*/
|
*/
|
||||||
@interface ASCollectionView : UICollectionView
|
@interface ASCollectionView : UICollectionView
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializer.
|
||||||
|
*
|
||||||
|
* @param layout The layout object to use for organizing items. The collection view stores a strong reference to the specified object. Must not be nil.
|
||||||
|
*/
|
||||||
- (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout *)layout;
|
- (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout *)layout;
|
||||||
|
- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout;
|
||||||
|
|
||||||
@property (nonatomic, weak) id<ASCollectionViewDataSource> asyncDataSource;
|
@property (nonatomic, weak) id<ASCollectionDelegate> asyncDelegate;
|
||||||
@property (nonatomic, weak) id<ASCollectionViewDelegate> asyncDelegate; // must not be nil
|
@property (nonatomic, weak) id<ASCollectionDataSource> asyncDataSource;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tuning parameters for a range type.
|
* Tuning parameters for a range type.
|
||||||
@@ -54,27 +60,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
*/
|
*/
|
||||||
- (void)setTuningParameters:(ASRangeTuningParameters)tuningParameters forRangeType:(ASLayoutRangeType)rangeType;
|
- (void)setTuningParameters:(ASRangeTuningParameters)tuningParameters forRangeType:(ASLayoutRangeType)rangeType;
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializer.
|
|
||||||
*
|
|
||||||
* @param frame The frame rectangle for the collection view, measured in points. The origin of the frame is relative to the superview
|
|
||||||
* in which you plan to add it. This frame is passed to the superclass during initialization.
|
|
||||||
*
|
|
||||||
* @param layout The layout object to use for organizing items. The collection view stores a strong reference to the specified object.
|
|
||||||
* Must not be nil.
|
|
||||||
*
|
|
||||||
* @param asyncDataFetchingEnabled Enable the data fetching in async mode.
|
|
||||||
*
|
|
||||||
* @discussion If asyncDataFetching is enabled, the `ASCollectionView` will fetch data through `collectionView:numberOfRowsInSection:` and
|
|
||||||
* `collectionView:nodeForRowAtIndexPath:` in async mode from background thread. Otherwise, the methods will be invoked synchronically
|
|
||||||
* from calling thread.
|
|
||||||
* Enabling asyncDataFetching could avoid blocking main thread for `ASCellNode` allocation, which is frequently reported issue for
|
|
||||||
* large scale data. On another hand, the application code need take the responsibility to avoid data inconsistence. Specifically,
|
|
||||||
* we will lock the data source through `collectionViewLockDataSource`, and unlock it by `collectionViewUnlockDataSource` after the data fetching.
|
|
||||||
* The application should not update the data source while the data source is locked, to keep data consistence.
|
|
||||||
*/
|
|
||||||
- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout asyncDataFetching:(BOOL)asyncDataFetchingEnabled;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The number of screens left to scroll before the delegate -collectionView:beginBatchFetchingWithContext: is called.
|
* The number of screens left to scroll before the delegate -collectionView:beginBatchFetchingWithContext: is called.
|
||||||
*
|
*
|
||||||
@@ -303,7 +288,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
/**
|
/**
|
||||||
* This is a node-based UICollectionViewDataSource.
|
* This is a node-based UICollectionViewDataSource.
|
||||||
*/
|
*/
|
||||||
@protocol ASCollectionViewDataSource <ASCommonCollectionViewDataSource, NSObject>
|
#define ASCollectionViewDataSource ASCollectionDataSource
|
||||||
|
@protocol ASCollectionDataSource <ASCommonCollectionViewDataSource, NSObject>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Similar to -collectionView:cellForItemAtIndexPath:.
|
* Similar to -collectionView:cellForItemAtIndexPath:.
|
||||||
@@ -364,7 +350,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
/**
|
/**
|
||||||
* This is a node-based UICollectionViewDelegate.
|
* This is a node-based UICollectionViewDelegate.
|
||||||
*/
|
*/
|
||||||
@protocol ASCollectionViewDelegate <ASCommonCollectionViewDelegate, NSObject>
|
#define ASCollectionViewDelegate ASCollectionDelegate
|
||||||
|
@protocol ASCollectionDelegate <ASCommonCollectionViewDelegate, NSObject>
|
||||||
|
|
||||||
@optional
|
@optional
|
||||||
|
|
||||||
@@ -433,4 +420,10 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@interface ASCollectionView (Deprecated)
|
||||||
|
|
||||||
|
- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout asyncDataFetching:(BOOL)asyncDataFetchingEnabled ASDISPLAYNODE_DEPRECATED;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
NS_ASSUME_NONNULL_END
|
||||||
|
|||||||
@@ -8,7 +8,9 @@
|
|||||||
|
|
||||||
#import "ASAssert.h"
|
#import "ASAssert.h"
|
||||||
#import "ASBatchFetching.h"
|
#import "ASBatchFetching.h"
|
||||||
|
#import "ASDelegateProxy.h"
|
||||||
#import "ASCollectionView.h"
|
#import "ASCollectionView.h"
|
||||||
|
#import "ASCollectionNode.h"
|
||||||
#import "ASCollectionDataController.h"
|
#import "ASCollectionDataController.h"
|
||||||
#import "ASCollectionViewLayoutController.h"
|
#import "ASCollectionViewLayoutController.h"
|
||||||
#import "ASCollectionViewFlowLayoutInspector.h"
|
#import "ASCollectionViewFlowLayoutInspector.h"
|
||||||
@@ -21,87 +23,6 @@ static const NSUInteger kASCollectionViewAnimationNone = UITableViewRowAnimation
|
|||||||
static const ASSizeRange kInvalidSizeRange = {CGSizeZero, CGSizeZero};
|
static const ASSizeRange kInvalidSizeRange = {CGSizeZero, CGSizeZero};
|
||||||
static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
|
static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
|
||||||
|
|
||||||
#pragma mark -
|
|
||||||
#pragma mark Proxying.
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ASCollectionView intercepts and/or overrides a few of UICollectionView's critical data source and delegate methods.
|
|
||||||
*
|
|
||||||
* Any selector included in this function *MUST* be implemented by ASCollectionView.
|
|
||||||
*/
|
|
||||||
static BOOL _isInterceptedSelector(SEL sel)
|
|
||||||
{
|
|
||||||
return (
|
|
||||||
// handled by ASCollectionView node<->cell machinery
|
|
||||||
sel == @selector(collectionView:cellForItemAtIndexPath:) ||
|
|
||||||
sel == @selector(collectionView:layout:sizeForItemAtIndexPath:) ||
|
|
||||||
sel == @selector(collectionView:viewForSupplementaryElementOfKind:atIndexPath:) ||
|
|
||||||
|
|
||||||
// handled by ASRangeController
|
|
||||||
sel == @selector(numberOfSectionsInCollectionView:) ||
|
|
||||||
sel == @selector(collectionView:numberOfItemsInSection:) ||
|
|
||||||
|
|
||||||
// used for ASRangeController visibility updates
|
|
||||||
sel == @selector(collectionView:willDisplayCell:forItemAtIndexPath:) ||
|
|
||||||
sel == @selector(collectionView:didEndDisplayingCell:forItemAtIndexPath:) ||
|
|
||||||
|
|
||||||
// used for batch fetching API
|
|
||||||
sel == @selector(scrollViewWillEndDragging:withVelocity:targetContentOffset:)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stand-in for UICollectionViewDataSource and UICollectionViewDelegate. Any method calls we intercept are routed to ASCollectionView;
|
|
||||||
* everything else leaves AsyncDisplayKit safely and arrives at the original intended data source and delegate.
|
|
||||||
*/
|
|
||||||
@interface _ASCollectionViewProxy : NSProxy
|
|
||||||
- (instancetype)initWithTarget:(id<NSObject>)target interceptor:(ASCollectionView *)interceptor;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation _ASCollectionViewProxy {
|
|
||||||
id<NSObject> __weak _target;
|
|
||||||
ASCollectionView * __weak _interceptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (instancetype)initWithTarget:(id<NSObject>)target interceptor:(ASCollectionView *)interceptor
|
|
||||||
{
|
|
||||||
// -[NSProxy init] is undefined
|
|
||||||
if (!self) {
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASDisplayNodeAssert(target, @"target must not be nil");
|
|
||||||
ASDisplayNodeAssert(interceptor, @"interceptor must not be nil");
|
|
||||||
|
|
||||||
_target = target;
|
|
||||||
_interceptor = interceptor;
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)respondsToSelector:(SEL)aSelector
|
|
||||||
{
|
|
||||||
ASDisplayNodeAssert(_target, @"target must not be nil"); // catch weak ref's being nilled early
|
|
||||||
ASDisplayNodeAssert(_interceptor, @"interceptor must not be nil");
|
|
||||||
|
|
||||||
return (_isInterceptedSelector(aSelector) || [_target respondsToSelector:aSelector]);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id)forwardingTargetForSelector:(SEL)aSelector
|
|
||||||
{
|
|
||||||
ASDisplayNodeAssert(_target, @"target must not be nil"); // catch weak ref's being nilled early
|
|
||||||
ASDisplayNodeAssert(_interceptor, @"interceptor must not be nil");
|
|
||||||
|
|
||||||
if (_isInterceptedSelector(aSelector)) {
|
|
||||||
return _interceptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
return [_target respondsToSelector:aSelector] ? _target : nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
#pragma mark ASCellNode<->UICollectionViewCell bridging.
|
#pragma mark ASCellNode<->UICollectionViewCell bridging.
|
||||||
|
|
||||||
@@ -137,24 +58,25 @@ static BOOL _isInterceptedSelector(SEL sel)
|
|||||||
#pragma mark -
|
#pragma mark -
|
||||||
#pragma mark ASCollectionView.
|
#pragma mark ASCollectionView.
|
||||||
|
|
||||||
@interface ASCollectionView () <ASRangeControllerDataSource, ASRangeControllerDelegate, ASDataControllerSource, ASCellNodeLayoutDelegate> {
|
@interface ASCollectionView () <ASRangeControllerDataSource, ASRangeControllerDelegate, ASDataControllerSource, ASCellNodeLayoutDelegate, ASDelegateProxyInterceptor> {
|
||||||
_ASCollectionViewProxy *_proxyDataSource;
|
ASCollectionViewProxy *_proxyDataSource;
|
||||||
_ASCollectionViewProxy *_proxyDelegate;
|
ASCollectionViewProxy *_proxyDelegate;
|
||||||
|
|
||||||
ASCollectionDataController *_dataController;
|
ASCollectionDataController *_dataController;
|
||||||
ASRangeController *_rangeController;
|
ASRangeController *_rangeController;
|
||||||
ASCollectionViewLayoutController *_layoutController;
|
ASCollectionViewLayoutController *_layoutController;
|
||||||
ASCollectionViewFlowLayoutInspector *_flowLayoutInspector;
|
ASCollectionViewFlowLayoutInspector *_flowLayoutInspector;
|
||||||
|
|
||||||
BOOL _performingBatchUpdates;
|
BOOL _performingBatchUpdates;
|
||||||
NSMutableArray *_batchUpdateBlocks;
|
NSMutableArray *_batchUpdateBlocks;
|
||||||
|
|
||||||
BOOL _asyncDataFetchingEnabled;
|
BOOL _asyncDataFetchingEnabled;
|
||||||
BOOL _asyncDelegateImplementsInsetSection;
|
BOOL _asyncDelegateImplementsInsetSection;
|
||||||
BOOL _collectionViewLayoutImplementsInsetSection;
|
BOOL _collectionViewLayoutImplementsInsetSection;
|
||||||
BOOL _asyncDataSourceImplementsConstrainedSizeForNode;
|
BOOL _asyncDataSourceImplementsConstrainedSizeForNode;
|
||||||
BOOL _queuedNodeSizeUpdate;
|
BOOL _queuedNodeSizeUpdate;
|
||||||
|
BOOL _isDeallocating;
|
||||||
|
|
||||||
ASBatchContext *_batchContext;
|
ASBatchContext *_batchContext;
|
||||||
|
|
||||||
CGSize _maxSizeForNodesConstrainedSize;
|
CGSize _maxSizeForNodesConstrainedSize;
|
||||||
@@ -172,7 +94,7 @@ static BOOL _isInterceptedSelector(SEL sel)
|
|||||||
* You will get an assertion failure saying `Invalid number of items in section 0.
|
* You will get an assertion failure saying `Invalid number of items in section 0.
|
||||||
* The number of items after the update (1) must be equal to the number of items before the update (1) plus or minus the items added and removed (1 added, 0 removed).`
|
* The number of items after the update (1) must be equal to the number of items before the update (1) plus or minus the items added and removed (1 added, 0 removed).`
|
||||||
* The collection view never queried your data source before the update to see that it actually had 0 items.
|
* The collection view never queried your data source before the update to see that it actually had 0 items.
|
||||||
*/
|
*/
|
||||||
BOOL _superIsPendingDataLoad;
|
BOOL _superIsPendingDataLoad;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,48 +109,51 @@ static BOOL _isInterceptedSelector(SEL sel)
|
|||||||
|
|
||||||
- (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout *)layout
|
- (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout *)layout
|
||||||
{
|
{
|
||||||
return [self initWithFrame:CGRectZero collectionViewLayout:layout asyncDataFetching:NO];
|
return [self initWithFrame:CGRectZero collectionViewLayout:layout];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout
|
- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout
|
||||||
{
|
{
|
||||||
return [self initWithFrame:frame collectionViewLayout:layout asyncDataFetching:NO];
|
ASCollectionNode *collectionNode = [[ASCollectionNode alloc] initWithFrame:frame collectionViewLayout:layout];
|
||||||
|
return collectionNode.view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: This method is deprecated and will probably be removed in or shortly after 2.0.
|
||||||
- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout asyncDataFetching:(BOOL)asyncDataFetchingEnabled
|
- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout asyncDataFetching:(BOOL)asyncDataFetchingEnabled
|
||||||
|
{
|
||||||
|
return [self initWithFrame:frame collectionViewLayout:layout];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)_initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout
|
||||||
{
|
{
|
||||||
if (!(self = [super initWithFrame:frame collectionViewLayout:layout]))
|
if (!(self = [super initWithFrame:frame collectionViewLayout:layout]))
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
// FIXME: asyncDataFetching is currently unreliable for some use cases.
|
|
||||||
// https://github.com/facebook/AsyncDisplayKit/issues/385
|
|
||||||
asyncDataFetchingEnabled = NO;
|
|
||||||
|
|
||||||
_layoutController = [[ASCollectionViewLayoutController alloc] initWithCollectionView:self];
|
_layoutController = [[ASCollectionViewLayoutController alloc] initWithCollectionView:self];
|
||||||
|
|
||||||
_rangeController = [[ASRangeController alloc] init];
|
_rangeController = [[ASRangeController alloc] init];
|
||||||
_rangeController.dataSource = self;
|
_rangeController.dataSource = self;
|
||||||
_rangeController.delegate = self;
|
_rangeController.delegate = self;
|
||||||
_rangeController.layoutController = _layoutController;
|
_rangeController.layoutController = _layoutController;
|
||||||
|
|
||||||
_dataController = [[ASCollectionDataController alloc] initWithAsyncDataFetching:asyncDataFetchingEnabled];
|
_dataController = [[ASCollectionDataController alloc] initWithAsyncDataFetching:NO];
|
||||||
_dataController.delegate = _rangeController;
|
_dataController.delegate = _rangeController;
|
||||||
_dataController.dataSource = self;
|
_dataController.dataSource = self;
|
||||||
|
|
||||||
_batchContext = [[ASBatchContext alloc] init];
|
_batchContext = [[ASBatchContext alloc] init];
|
||||||
|
|
||||||
_leadingScreensForBatching = 1.0;
|
_leadingScreensForBatching = 1.0;
|
||||||
|
|
||||||
_asyncDataFetchingEnabled = asyncDataFetchingEnabled;
|
_asyncDataFetchingEnabled = NO;
|
||||||
_asyncDataSourceLocked = NO;
|
_asyncDataSourceLocked = NO;
|
||||||
|
|
||||||
_performingBatchUpdates = NO;
|
_performingBatchUpdates = NO;
|
||||||
_batchUpdateBlocks = [NSMutableArray array];
|
_batchUpdateBlocks = [NSMutableArray array];
|
||||||
|
|
||||||
_superIsPendingDataLoad = YES;
|
_superIsPendingDataLoad = YES;
|
||||||
|
|
||||||
_collectionViewLayoutImplementsInsetSection = [layout respondsToSelector:@selector(sectionInset)];
|
_collectionViewLayoutImplementsInsetSection = [layout respondsToSelector:@selector(sectionInset)];
|
||||||
|
|
||||||
_maxSizeForNodesConstrainedSize = self.bounds.size;
|
_maxSizeForNodesConstrainedSize = self.bounds.size;
|
||||||
// If the initial size is 0, expect a size change very soon which is part of the initial configuration
|
// If the initial size is 0, expect a size change very soon which is part of the initial configuration
|
||||||
// and should not trigger a relayout.
|
// and should not trigger a relayout.
|
||||||
@@ -240,6 +165,12 @@ static BOOL _isInterceptedSelector(SEL sel)
|
|||||||
_layoutInspector = [self flowLayoutInspector];
|
_layoutInspector = [self flowLayoutInspector];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_proxyDelegate = [[ASCollectionViewProxy alloc] initWithTarget:nil interceptor:self];
|
||||||
|
super.delegate = (id<UICollectionViewDelegate>)_proxyDelegate;
|
||||||
|
|
||||||
|
_proxyDataSource = [[ASCollectionViewProxy alloc] initWithTarget:nil interceptor:self];
|
||||||
|
super.dataSource = (id<UICollectionViewDataSource>)_proxyDataSource;
|
||||||
|
|
||||||
_registeredSupplementaryKinds = [NSMutableSet set];
|
_registeredSupplementaryKinds = [NSMutableSet set];
|
||||||
|
|
||||||
self.backgroundColor = [UIColor whiteColor];
|
self.backgroundColor = [UIColor whiteColor];
|
||||||
@@ -251,10 +182,10 @@ static BOOL _isInterceptedSelector(SEL sel)
|
|||||||
|
|
||||||
- (void)dealloc
|
- (void)dealloc
|
||||||
{
|
{
|
||||||
// Sometimes the UIKit classes can call back to their delegate even during deallocation.
|
// Sometimes the UIKit classes can call back to their delegate even during deallocation, due to animation completion blocks etc.
|
||||||
// This bug might be iOS 7-specific.
|
_isDeallocating = YES;
|
||||||
super.delegate = nil;
|
[self setAsyncDelegate:nil];
|
||||||
super.dataSource = nil;
|
[self setAsyncDataSource:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -262,13 +193,13 @@ static BOOL _isInterceptedSelector(SEL sel)
|
|||||||
*/
|
*/
|
||||||
- (ASCollectionViewFlowLayoutInspector *)flowLayoutInspector
|
- (ASCollectionViewFlowLayoutInspector *)flowLayoutInspector
|
||||||
{
|
{
|
||||||
if (_flowLayoutInspector == nil) {
|
if (_flowLayoutInspector == nil) {
|
||||||
UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)self.collectionViewLayout;
|
UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)self.collectionViewLayout;
|
||||||
ASDisplayNodeAssertNotNil(layout, @"Collection view layout must be a flow layout to use the built-in inspector");
|
ASDisplayNodeAssertNotNil(layout, @"Collection view layout must be a flow layout to use the built-in inspector");
|
||||||
_flowLayoutInspector = [[ASCollectionViewFlowLayoutInspector alloc] initWithCollectionView:self
|
_flowLayoutInspector = [[ASCollectionViewFlowLayoutInspector alloc] initWithCollectionView:self
|
||||||
flowLayout:layout];
|
flowLayout:layout];
|
||||||
}
|
}
|
||||||
return _flowLayoutInspector;
|
return _flowLayoutInspector;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
@@ -308,24 +239,35 @@ static BOOL _isInterceptedSelector(SEL sel)
|
|||||||
ASDisplayNodeAssert(delegate == nil, @"ASCollectionView uses asyncDelegate, not UICollectionView's delegate property.");
|
ASDisplayNodeAssert(delegate == nil, @"ASCollectionView uses asyncDelegate, not UICollectionView's delegate property.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)proxyTargetHasDeallocated:(ASDelegateProxy *)proxy
|
||||||
|
{
|
||||||
|
if (proxy == _proxyDelegate) {
|
||||||
|
[self setAsyncDelegate:nil];
|
||||||
|
} else if (proxy == _proxyDataSource) {
|
||||||
|
[self setAsyncDataSource:nil];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (void)setAsyncDataSource:(id<ASCollectionViewDataSource>)asyncDataSource
|
- (void)setAsyncDataSource:(id<ASCollectionViewDataSource>)asyncDataSource
|
||||||
{
|
{
|
||||||
// Note: It's common to check if the value hasn't changed and short-circuit but we aren't doing that here to handle
|
// Note: It's common to check if the value hasn't changed and short-circuit but we aren't doing that here to handle
|
||||||
// the (common) case of nilling the asyncDataSource in the ViewController's dealloc. In this case our _asyncDataSource
|
// the (common) case of nilling the asyncDataSource in the ViewController's dealloc. In this case our _asyncDataSource
|
||||||
// will return as nil (ARC magic) even though the _proxyDataSource still exists. It's really important to nil out
|
// will return as nil (ARC magic) even though the _proxyDataSource still exists. It's really important to nil out
|
||||||
// super.dataSource in this case because calls to _ASTableViewProxy will start failing and cause crashes.
|
// super.dataSource in this case because calls to ASCollectionViewProxy will start failing and cause crashes.
|
||||||
|
|
||||||
|
super.dataSource = nil;
|
||||||
|
|
||||||
if (asyncDataSource == nil) {
|
if (asyncDataSource == nil) {
|
||||||
super.dataSource = nil;
|
|
||||||
_asyncDataSource = nil;
|
_asyncDataSource = nil;
|
||||||
_proxyDataSource = nil;
|
_proxyDataSource = _isDeallocating ? nil : [[ASCollectionViewProxy alloc] initWithTarget:nil interceptor:self];
|
||||||
_asyncDataSourceImplementsConstrainedSizeForNode = NO;
|
_asyncDataSourceImplementsConstrainedSizeForNode = NO;
|
||||||
} else {
|
} else {
|
||||||
_asyncDataSource = asyncDataSource;
|
_asyncDataSource = asyncDataSource;
|
||||||
_proxyDataSource = [[_ASCollectionViewProxy alloc] initWithTarget:_asyncDataSource interceptor:self];
|
_proxyDataSource = [[ASCollectionViewProxy alloc] initWithTarget:_asyncDataSource interceptor:self];
|
||||||
super.dataSource = (id<UICollectionViewDataSource>)_proxyDataSource;
|
|
||||||
_asyncDataSourceImplementsConstrainedSizeForNode = ([_asyncDataSource respondsToSelector:@selector(collectionView:constrainedSizeForNodeAtIndexPath:)] ? 1 : 0);
|
_asyncDataSourceImplementsConstrainedSizeForNode = ([_asyncDataSource respondsToSelector:@selector(collectionView:constrainedSizeForNodeAtIndexPath:)] ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
super.dataSource = (id<UICollectionViewDataSource>)_proxyDataSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setAsyncDelegate:(id<ASCollectionViewDelegate>)asyncDelegate
|
- (void)setAsyncDelegate:(id<ASCollectionViewDelegate>)asyncDelegate
|
||||||
@@ -333,22 +275,25 @@ static BOOL _isInterceptedSelector(SEL sel)
|
|||||||
// Note: It's common to check if the value hasn't changed and short-circuit but we aren't doing that here to handle
|
// Note: It's common to check if the value hasn't changed and short-circuit but we aren't doing that here to handle
|
||||||
// the (common) case of nilling the asyncDelegate in the ViewController's dealloc. In this case our _asyncDelegate
|
// the (common) case of nilling the asyncDelegate in the ViewController's dealloc. In this case our _asyncDelegate
|
||||||
// will return as nil (ARC magic) even though the _proxyDelegate still exists. It's really important to nil out
|
// will return as nil (ARC magic) even though the _proxyDelegate still exists. It's really important to nil out
|
||||||
// super.delegate in this case because calls to _ASTableViewProxy will start failing and cause crashes.
|
// super.delegate in this case because calls to ASCollectionViewProxy will start failing and cause crashes.
|
||||||
|
|
||||||
|
// Order is important here, the asyncDelegate must be callable while nilling super.delegate to avoid random crashes
|
||||||
|
// in UIScrollViewAccessibility.
|
||||||
|
|
||||||
|
super.delegate = nil;
|
||||||
|
|
||||||
if (asyncDelegate == nil) {
|
if (asyncDelegate == nil) {
|
||||||
// order is important here, the delegate must be callable while nilling super.delegate to avoid random crashes
|
|
||||||
// in UIScrollViewAccessibility.
|
|
||||||
super.delegate = nil;
|
|
||||||
_asyncDelegate = nil;
|
_asyncDelegate = nil;
|
||||||
_proxyDelegate = nil;
|
_proxyDelegate = _isDeallocating ? nil : [[ASCollectionViewProxy alloc] initWithTarget:nil interceptor:self];
|
||||||
_asyncDelegateImplementsInsetSection = NO;
|
_asyncDelegateImplementsInsetSection = NO;
|
||||||
} else {
|
} else {
|
||||||
_asyncDelegate = asyncDelegate;
|
_asyncDelegate = asyncDelegate;
|
||||||
_proxyDelegate = [[_ASCollectionViewProxy alloc] initWithTarget:_asyncDelegate interceptor:self];
|
_proxyDelegate = [[ASCollectionViewProxy alloc] initWithTarget:_asyncDelegate interceptor:self];
|
||||||
super.delegate = (id<UICollectionViewDelegate>)_proxyDelegate;
|
|
||||||
_asyncDelegateImplementsInsetSection = ([_asyncDelegate respondsToSelector:@selector(collectionView:layout:insetForSectionAtIndex:)] ? 1 : 0);
|
_asyncDelegateImplementsInsetSection = ([_asyncDelegate respondsToSelector:@selector(collectionView:layout:insetForSectionAtIndex:)] ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
super.delegate = (id<UICollectionViewDelegate>)_proxyDelegate;
|
||||||
|
|
||||||
[_layoutInspector didChangeCollectionViewDelegate:asyncDelegate];
|
[_layoutInspector didChangeCollectionViewDelegate:asyncDelegate];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -409,7 +354,7 @@ static BOOL _isInterceptedSelector(SEL sel)
|
|||||||
- (void)performBatchAnimated:(BOOL)animated updates:(void (^)())updates completion:(void (^)(BOOL))completion
|
- (void)performBatchAnimated:(BOOL)animated updates:(void (^)())updates completion:(void (^)(BOOL))completion
|
||||||
{
|
{
|
||||||
ASDisplayNodeAssertMainThread();
|
ASDisplayNodeAssertMainThread();
|
||||||
|
|
||||||
[_dataController beginUpdates];
|
[_dataController beginUpdates];
|
||||||
updates();
|
updates();
|
||||||
[_dataController endUpdatesAnimated:animated completion:completion];
|
[_dataController endUpdatesAnimated:animated completion:completion];
|
||||||
@@ -487,7 +432,7 @@ static BOOL _isInterceptedSelector(SEL sel)
|
|||||||
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
|
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
|
||||||
{
|
{
|
||||||
_ASCollectionViewCell *cell = [self dequeueReusableCellWithReuseIdentifier:kCellReuseIdentifier forIndexPath:indexPath];
|
_ASCollectionViewCell *cell = [self dequeueReusableCellWithReuseIdentifier:kCellReuseIdentifier forIndexPath:indexPath];
|
||||||
|
|
||||||
ASCellNode *node = [_dataController nodeAtIndexPath:indexPath];
|
ASCellNode *node = [_dataController nodeAtIndexPath:indexPath];
|
||||||
cell.node = node;
|
cell.node = node;
|
||||||
[_rangeController configureContentView:cell.contentView forCellNode:node];
|
[_rangeController configureContentView:cell.contentView forCellNode:node];
|
||||||
@@ -524,7 +469,7 @@ static BOOL _isInterceptedSelector(SEL sel)
|
|||||||
CGPoint scrollVelocity = [self.panGestureRecognizer velocityInView:self.superview];
|
CGPoint scrollVelocity = [self.panGestureRecognizer velocityInView:self.superview];
|
||||||
return [self scrollDirectionForVelocity:scrollVelocity];
|
return [self scrollDirectionForVelocity:scrollVelocity];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (ASScrollDirection)scrollDirectionForVelocity:(CGPoint)scrollVelocity
|
- (ASScrollDirection)scrollDirectionForVelocity:(CGPoint)scrollVelocity
|
||||||
{
|
{
|
||||||
ASScrollDirection direction = ASScrollDirectionNone;
|
ASScrollDirection direction = ASScrollDirectionNone;
|
||||||
@@ -544,7 +489,7 @@ static BOOL _isInterceptedSelector(SEL sel)
|
|||||||
direction |= ASScrollDirectionUp;
|
direction |= ASScrollDirectionUp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return direction;
|
return direction;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -623,7 +568,7 @@ static BOOL _isInterceptedSelector(SEL sel)
|
|||||||
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
|
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
|
||||||
{
|
{
|
||||||
[self handleBatchFetchScrollingToOffset:*targetContentOffset];
|
[self handleBatchFetchScrollingToOffset:*targetContentOffset];
|
||||||
|
|
||||||
if ([_asyncDelegate respondsToSelector:@selector(scrollViewWillEndDragging:withVelocity:targetContentOffset:)]) {
|
if ([_asyncDelegate respondsToSelector:@selector(scrollViewWillEndDragging:withVelocity:targetContentOffset:)]) {
|
||||||
[_asyncDelegate scrollViewWillEndDragging:scrollView withVelocity:velocity targetContentOffset:targetContentOffset];
|
[_asyncDelegate scrollViewWillEndDragging:scrollView withVelocity:velocity targetContentOffset:targetContentOffset];
|
||||||
}
|
}
|
||||||
@@ -643,11 +588,11 @@ static BOOL _isInterceptedSelector(SEL sel)
|
|||||||
- (void)handleBatchFetchScrollingToOffset:(CGPoint)targetOffset
|
- (void)handleBatchFetchScrollingToOffset:(CGPoint)targetOffset
|
||||||
{
|
{
|
||||||
ASDisplayNodeAssert(_batchContext != nil, @"Batch context should exist");
|
ASDisplayNodeAssert(_batchContext != nil, @"Batch context should exist");
|
||||||
|
|
||||||
if (![self shouldBatchFetch]) {
|
if (![self shouldBatchFetch]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ASDisplayShouldFetchBatchForContext(_batchContext, [self scrollDirection], self.bounds, self.contentSize, targetOffset, _leadingScreensForBatching)) {
|
if (ASDisplayShouldFetchBatchForContext(_batchContext, [self scrollDirection], self.bounds, self.contentSize, targetOffset, _leadingScreensForBatching)) {
|
||||||
[_batchContext beginBatchFetching];
|
[_batchContext beginBatchFetching];
|
||||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||||
@@ -695,7 +640,7 @@ static BOOL _isInterceptedSelector(SEL sel)
|
|||||||
}
|
}
|
||||||
constrainedSize = ASSizeRangeMake(CGSizeZero, maxSize);
|
constrainedSize = ASSizeRangeMake(CGSizeZero, maxSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
UIEdgeInsets sectionInset = UIEdgeInsetsZero;
|
UIEdgeInsets sectionInset = UIEdgeInsetsZero;
|
||||||
if (_collectionViewLayoutImplementsInsetSection) {
|
if (_collectionViewLayoutImplementsInsetSection) {
|
||||||
sectionInset = [(UICollectionViewFlowLayout *)self.collectionViewLayout sectionInset];
|
sectionInset = [(UICollectionViewFlowLayout *)self.collectionViewLayout sectionInset];
|
||||||
@@ -704,7 +649,7 @@ static BOOL _isInterceptedSelector(SEL sel)
|
|||||||
if (_asyncDelegateImplementsInsetSection) {
|
if (_asyncDelegateImplementsInsetSection) {
|
||||||
sectionInset = [(id<ASCollectionViewDelegateFlowLayout>)_asyncDelegate collectionView:self layout:self.collectionViewLayout insetForSectionAtIndex:indexPath.section];
|
sectionInset = [(id<ASCollectionViewDelegateFlowLayout>)_asyncDelegate collectionView:self layout:self.collectionViewLayout insetForSectionAtIndex:indexPath.section];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ASScrollDirectionContainsHorizontalDirection([self scrollableDirections])) {
|
if (ASScrollDirectionContainsHorizontalDirection([self scrollableDirections])) {
|
||||||
constrainedSize.min.width = MAX(0, constrainedSize.min.width - sectionInset.left - sectionInset.right);
|
constrainedSize.min.width = MAX(0, constrainedSize.min.width - sectionInset.left - sectionInset.right);
|
||||||
//ignore insets for FLT_MAX so FLT_MAX can be compared against
|
//ignore insets for FLT_MAX so FLT_MAX can be compared against
|
||||||
@@ -718,7 +663,7 @@ static BOOL _isInterceptedSelector(SEL sel)
|
|||||||
constrainedSize.max.height = MAX(0, constrainedSize.max.height - sectionInset.top - sectionInset.bottom);
|
constrainedSize.max.height = MAX(0, constrainedSize.max.height - sectionInset.top - sectionInset.bottom);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return constrainedSize;
|
return constrainedSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -738,7 +683,7 @@ static BOOL _isInterceptedSelector(SEL sel)
|
|||||||
- (void)dataControllerLockDataSource
|
- (void)dataControllerLockDataSource
|
||||||
{
|
{
|
||||||
ASDisplayNodeAssert(!self.asyncDataSourceLocked, @"The data source has already been locked");
|
ASDisplayNodeAssert(!self.asyncDataSourceLocked, @"The data source has already been locked");
|
||||||
|
|
||||||
self.asyncDataSourceLocked = YES;
|
self.asyncDataSourceLocked = YES;
|
||||||
if ([_asyncDataSource respondsToSelector:@selector(collectionViewLockDataSource:)]) {
|
if ([_asyncDataSource respondsToSelector:@selector(collectionViewLockDataSource:)]) {
|
||||||
[_asyncDataSource collectionViewLockDataSource:self];
|
[_asyncDataSource collectionViewLockDataSource:self];
|
||||||
@@ -748,7 +693,7 @@ static BOOL _isInterceptedSelector(SEL sel)
|
|||||||
- (void)dataControllerUnlockDataSource
|
- (void)dataControllerUnlockDataSource
|
||||||
{
|
{
|
||||||
ASDisplayNodeAssert(self.asyncDataSourceLocked, @"The data source has already been unlocked");
|
ASDisplayNodeAssert(self.asyncDataSourceLocked, @"The data source has already been unlocked");
|
||||||
|
|
||||||
self.asyncDataSourceLocked = NO;
|
self.asyncDataSourceLocked = NO;
|
||||||
if ([_asyncDataSource respondsToSelector:@selector(collectionViewUnlockDataSource:)]) {
|
if ([_asyncDataSource respondsToSelector:@selector(collectionViewUnlockDataSource:)]) {
|
||||||
[_asyncDataSource collectionViewUnlockDataSource:self];
|
[_asyncDataSource collectionViewUnlockDataSource:self];
|
||||||
@@ -817,7 +762,7 @@ static BOOL _isInterceptedSelector(SEL sel)
|
|||||||
- (void)rangeController:(ASRangeController *)rangeController didEndUpdatesAnimated:(BOOL)animated completion:(void (^)(BOOL))completion
|
- (void)rangeController:(ASRangeController *)rangeController didEndUpdatesAnimated:(BOOL)animated completion:(void (^)(BOOL))completion
|
||||||
{
|
{
|
||||||
ASDisplayNodeAssertMainThread();
|
ASDisplayNodeAssertMainThread();
|
||||||
|
|
||||||
if (!self.asyncDataSource || _superIsPendingDataLoad) {
|
if (!self.asyncDataSource || _superIsPendingDataLoad) {
|
||||||
if (completion) {
|
if (completion) {
|
||||||
completion(NO);
|
completion(NO);
|
||||||
@@ -832,7 +777,7 @@ static BOOL _isInterceptedSelector(SEL sel)
|
|||||||
}
|
}
|
||||||
} completion:completion];
|
} completion:completion];
|
||||||
});
|
});
|
||||||
|
|
||||||
[_batchUpdateBlocks removeAllObjects];
|
[_batchUpdateBlocks removeAllObjects];
|
||||||
_performingBatchUpdates = NO;
|
_performingBatchUpdates = NO;
|
||||||
}
|
}
|
||||||
@@ -840,11 +785,11 @@ static BOOL _isInterceptedSelector(SEL sel)
|
|||||||
- (void)rangeController:(ASRangeController *)rangeController didInsertNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
|
- (void)rangeController:(ASRangeController *)rangeController didInsertNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
|
||||||
{
|
{
|
||||||
ASDisplayNodeAssertMainThread();
|
ASDisplayNodeAssertMainThread();
|
||||||
|
|
||||||
if (!self.asyncDataSource || _superIsPendingDataLoad) {
|
if (!self.asyncDataSource || _superIsPendingDataLoad) {
|
||||||
return; // if the asyncDataSource has become invalid while we are processing, ignore this request to avoid crashes
|
return; // if the asyncDataSource has become invalid while we are processing, ignore this request to avoid crashes
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_performingBatchUpdates) {
|
if (_performingBatchUpdates) {
|
||||||
[_batchUpdateBlocks addObject:^{
|
[_batchUpdateBlocks addObject:^{
|
||||||
[super insertItemsAtIndexPaths:indexPaths];
|
[super insertItemsAtIndexPaths:indexPaths];
|
||||||
@@ -859,11 +804,11 @@ static BOOL _isInterceptedSelector(SEL sel)
|
|||||||
- (void)rangeController:(ASRangeController *)rangeController didDeleteNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
|
- (void)rangeController:(ASRangeController *)rangeController didDeleteNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
|
||||||
{
|
{
|
||||||
ASDisplayNodeAssertMainThread();
|
ASDisplayNodeAssertMainThread();
|
||||||
|
|
||||||
if (!self.asyncDataSource || _superIsPendingDataLoad) {
|
if (!self.asyncDataSource || _superIsPendingDataLoad) {
|
||||||
return; // if the asyncDataSource has become invalid while we are processing, ignore this request to avoid crashes
|
return; // if the asyncDataSource has become invalid while we are processing, ignore this request to avoid crashes
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_performingBatchUpdates) {
|
if (_performingBatchUpdates) {
|
||||||
[_batchUpdateBlocks addObject:^{
|
[_batchUpdateBlocks addObject:^{
|
||||||
[super deleteItemsAtIndexPaths:indexPaths];
|
[super deleteItemsAtIndexPaths:indexPaths];
|
||||||
@@ -878,11 +823,11 @@ static BOOL _isInterceptedSelector(SEL sel)
|
|||||||
- (void)rangeController:(ASRangeController *)rangeController didInsertSectionsAtIndexSet:(NSIndexSet *)indexSet withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
|
- (void)rangeController:(ASRangeController *)rangeController didInsertSectionsAtIndexSet:(NSIndexSet *)indexSet withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
|
||||||
{
|
{
|
||||||
ASDisplayNodeAssertMainThread();
|
ASDisplayNodeAssertMainThread();
|
||||||
|
|
||||||
if (!self.asyncDataSource || _superIsPendingDataLoad) {
|
if (!self.asyncDataSource || _superIsPendingDataLoad) {
|
||||||
return; // if the asyncDataSource has become invalid while we are processing, ignore this request to avoid crashes
|
return; // if the asyncDataSource has become invalid while we are processing, ignore this request to avoid crashes
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_performingBatchUpdates) {
|
if (_performingBatchUpdates) {
|
||||||
[_batchUpdateBlocks addObject:^{
|
[_batchUpdateBlocks addObject:^{
|
||||||
[super insertSections:indexSet];
|
[super insertSections:indexSet];
|
||||||
@@ -897,11 +842,11 @@ static BOOL _isInterceptedSelector(SEL sel)
|
|||||||
- (void)rangeController:(ASRangeController *)rangeController didDeleteSectionsAtIndexSet:(NSIndexSet *)indexSet withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
|
- (void)rangeController:(ASRangeController *)rangeController didDeleteSectionsAtIndexSet:(NSIndexSet *)indexSet withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
|
||||||
{
|
{
|
||||||
ASDisplayNodeAssertMainThread();
|
ASDisplayNodeAssertMainThread();
|
||||||
|
|
||||||
if (!self.asyncDataSource || _superIsPendingDataLoad) {
|
if (!self.asyncDataSource || _superIsPendingDataLoad) {
|
||||||
return; // if the asyncDataSource has become invalid while we are processing, ignore this request to avoid crashes
|
return; // if the asyncDataSource has become invalid while we are processing, ignore this request to avoid crashes
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_performingBatchUpdates) {
|
if (_performingBatchUpdates) {
|
||||||
[_batchUpdateBlocks addObject:^{
|
[_batchUpdateBlocks addObject:^{
|
||||||
[super deleteSections:indexSet];
|
[super deleteSections:indexSet];
|
||||||
@@ -918,11 +863,11 @@ static BOOL _isInterceptedSelector(SEL sel)
|
|||||||
- (void)nodeDidRelayout:(ASCellNode *)node sizeChanged:(BOOL)sizeChanged
|
- (void)nodeDidRelayout:(ASCellNode *)node sizeChanged:(BOOL)sizeChanged
|
||||||
{
|
{
|
||||||
ASDisplayNodeAssertMainThread();
|
ASDisplayNodeAssertMainThread();
|
||||||
|
|
||||||
if (!sizeChanged || _queuedNodeSizeUpdate) {
|
if (!sizeChanged || _queuedNodeSizeUpdate) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_queuedNodeSizeUpdate = YES;
|
_queuedNodeSizeUpdate = YES;
|
||||||
[self performSelector:@selector(requeryNodeSizes)
|
[self performSelector:@selector(requeryNodeSizes)
|
||||||
withObject:nil
|
withObject:nil
|
||||||
@@ -934,7 +879,7 @@ static BOOL _isInterceptedSelector(SEL sel)
|
|||||||
- (void)requeryNodeSizes
|
- (void)requeryNodeSizes
|
||||||
{
|
{
|
||||||
_queuedNodeSizeUpdate = NO;
|
_queuedNodeSizeUpdate = NO;
|
||||||
|
|
||||||
[super performBatchUpdates:^{} completion:nil];
|
[super performBatchUpdates:^{} completion:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -944,7 +889,7 @@ static BOOL _isInterceptedSelector(SEL sel)
|
|||||||
{
|
{
|
||||||
for (NSArray *section in [_dataController completedNodes]) {
|
for (NSArray *section in [_dataController completedNodes]) {
|
||||||
for (ASDisplayNode *node in section) {
|
for (ASDisplayNode *node in section) {
|
||||||
[node recursivelyClearContents];
|
[node exitInterfaceState:ASInterfaceStateDisplay];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -953,7 +898,7 @@ static BOOL _isInterceptedSelector(SEL sel)
|
|||||||
{
|
{
|
||||||
for (NSArray *section in [_dataController completedNodes]) {
|
for (NSArray *section in [_dataController completedNodes]) {
|
||||||
for (ASDisplayNode *node in section) {
|
for (ASDisplayNode *node in section) {
|
||||||
[node recursivelyClearFetchedData];
|
[node exitInterfaceState:ASInterfaceStateFetchData];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,7 +76,6 @@ void _ASEnumerateControlEventsIncludedInMaskWithBlock(ASControlNodeEvent mask, v
|
|||||||
if (!(self = [super init]))
|
if (!(self = [super init]))
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
_controlEventDispatchTable = [[NSMutableDictionary alloc] initWithCapacity:kASControlNodeEventDispatchTableInitialCapacity]; // enough to handle common types without re-hashing the dictionary when adding entries.
|
|
||||||
_enabled = YES;
|
_enabled = YES;
|
||||||
|
|
||||||
// As we have no targets yet, we start off with user interaction off. When a target is added, it'll get turned back on.
|
// As we have no targets yet, we start off with user interaction off. When a target is added, it'll get turned back on.
|
||||||
@@ -214,6 +213,10 @@ void _ASEnumerateControlEventsIncludedInMaskWithBlock(ASControlNodeEvent mask, v
|
|||||||
// Convert nil to [NSNull null] so that it can be used as a key for NSMapTable.
|
// Convert nil to [NSNull null] so that it can be used as a key for NSMapTable.
|
||||||
if (!target)
|
if (!target)
|
||||||
target = [NSNull null];
|
target = [NSNull null];
|
||||||
|
|
||||||
|
if (!_controlEventDispatchTable) {
|
||||||
|
_controlEventDispatchTable = [[NSMutableDictionary alloc] initWithCapacity:kASControlNodeEventDispatchTableInitialCapacity]; // enough to handle common types without re-hashing the dictionary when adding entries.
|
||||||
|
}
|
||||||
|
|
||||||
// Enumerate the events in the mask, adding the target-action pair for each control event included in controlEventMask
|
// Enumerate the events in the mask, adding the target-action pair for each control event included in controlEventMask
|
||||||
_ASEnumerateControlEventsIncludedInMaskWithBlock(controlEventMask, ^
|
_ASEnumerateControlEventsIncludedInMaskWithBlock(controlEventMask, ^
|
||||||
|
|||||||
@@ -39,35 +39,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
|
|
||||||
@interface ASDisplayNode (Subclassing)
|
@interface ASDisplayNode (Subclassing)
|
||||||
|
|
||||||
|
|
||||||
/** @name View Configuration */
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The view class to use when creating a new display node instance. Defaults to _ASDisplayView.
|
|
||||||
*/
|
|
||||||
+ (Class)viewClass;
|
|
||||||
|
|
||||||
|
|
||||||
/** @name Properties */
|
/** @name Properties */
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @abstract The scale factor to apply to the rendering.
|
|
||||||
*
|
|
||||||
* @discussion Use setNeedsDisplayAtScale: to set a value and then after display, the display node will set the layer's
|
|
||||||
* contentsScale. This is to prevent jumps when re-rasterizing at a different contentsScale.
|
|
||||||
* Read this property if you need to know the future contentsScale of your layer, eg in drawParameters.
|
|
||||||
*
|
|
||||||
* @see setNeedsDisplayAtScale:
|
|
||||||
*/
|
|
||||||
@property (nonatomic, assign, readonly) CGFloat contentsScaleForDisplay;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @abstract Whether the view or layer of this display node is currently in a window
|
|
||||||
*/
|
|
||||||
@property (nonatomic, readonly, assign, getter=isInHierarchy) BOOL inHierarchy;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @abstract Return the calculated layout.
|
* @abstract Return the calculated layout.
|
||||||
*
|
*
|
||||||
@@ -192,10 +165,9 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
*
|
*
|
||||||
* @note Called on the display queue and/or main queue (MUST BE THREAD SAFE)
|
* @note Called on the display queue and/or main queue (MUST BE THREAD SAFE)
|
||||||
*/
|
*/
|
||||||
+ (void)drawRect:(CGRect)bounds
|
+ (void)drawRect:(CGRect)bounds withParameters:(nullable id <NSObject>)parameters
|
||||||
withParameters:(nullable id<NSObject>)parameters
|
isCancelled:(asdisplaynode_iscancelled_block_t)isCancelledBlock
|
||||||
isCancelled:(asdisplaynode_iscancelled_block_t)isCancelledBlock
|
isRasterizing:(BOOL)isRasterizing;
|
||||||
isRasterizing:(BOOL)isRasterizing;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @summary Delegate override to provide new layer contents as a UIImage.
|
* @summary Delegate override to provide new layer contents as a UIImage.
|
||||||
@@ -238,6 +210,33 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
*/
|
*/
|
||||||
- (void)displayDidFinish ASDISPLAYNODE_REQUIRES_SUPER;
|
- (void)displayDidFinish ASDISPLAYNODE_REQUIRES_SUPER;
|
||||||
|
|
||||||
|
/** @name Observing node-related changes */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @abstract Called whenever any bit in the ASInterfaceState bitfield is changed.
|
||||||
|
*
|
||||||
|
* @discussion Subclasses may use this to monitor when they become visible, should free cached data, and much more.
|
||||||
|
* @see ASInterfaceState
|
||||||
|
*/
|
||||||
|
- (void)interfaceStateDidChange:(ASInterfaceState)newState fromState:(ASInterfaceState)oldState;
|
||||||
|
|
||||||
|
- (void)visibilityDidChange:(BOOL)isVisible;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called just before the view is added to a window.
|
||||||
|
*/
|
||||||
|
- (void)willEnterHierarchy ASDISPLAYNODE_REQUIRES_SUPER;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called after the view is removed from the window.
|
||||||
|
*/
|
||||||
|
- (void)didExitHierarchy ASDISPLAYNODE_REQUIRES_SUPER;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @abstract Whether the view or layer of this display node is currently in a window
|
||||||
|
*/
|
||||||
|
@property (nonatomic, readonly, assign, getter=isInHierarchy) BOOL inHierarchy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @abstract Indicates that the node should fetch any external data, such as images.
|
* @abstract Indicates that the node should fetch any external data, such as images.
|
||||||
*
|
*
|
||||||
@@ -247,6 +246,23 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
*/
|
*/
|
||||||
- (void)fetchData ASDISPLAYNODE_REQUIRES_SUPER;
|
- (void)fetchData ASDISPLAYNODE_REQUIRES_SUPER;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides an opportunity to clear any fetched data (e.g. remote / network or database-queried) on the current node.
|
||||||
|
*
|
||||||
|
* @discussion This will not clear data recursively for all subnodes. Either call -recursivelyClearFetchedData or
|
||||||
|
* selectively clear fetched data.
|
||||||
|
*/
|
||||||
|
- (void)clearFetchedData ASDISPLAYNODE_REQUIRES_SUPER;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides an opportunity to clear backing store and other memory-intensive intermediates, such as text layout managers
|
||||||
|
* on the current node.
|
||||||
|
*
|
||||||
|
* @discussion Called by -recursivelyClearContents. Base class implements self.contents = nil, clearing any backing
|
||||||
|
* store, for asynchronous regeneration when needed.
|
||||||
|
*/
|
||||||
|
- (void)clearContents 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.
|
||||||
@@ -269,7 +285,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
*/
|
*/
|
||||||
- (void)subnodeDisplayDidFinish:(ASDisplayNode *)subnode ASDISPLAYNODE_REQUIRES_SUPER;
|
- (void)subnodeDisplayDidFinish:(ASDisplayNode *)subnode ASDISPLAYNODE_REQUIRES_SUPER;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @abstract Marks the receiver's bounds as needing to be redrawn, with a scale value.
|
* @abstract Marks the receiver's bounds as needing to be redrawn, with a scale value.
|
||||||
*
|
*
|
||||||
@@ -297,6 +312,17 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
*/
|
*/
|
||||||
- (void)recursivelySetNeedsDisplayAtScale:(CGFloat)contentsScale;
|
- (void)recursivelySetNeedsDisplayAtScale:(CGFloat)contentsScale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @abstract The scale factor to apply to the rendering.
|
||||||
|
*
|
||||||
|
* @discussion Use setNeedsDisplayAtScale: to set a value and then after display, the display node will set the layer's
|
||||||
|
* contentsScale. This is to prevent jumps when re-rasterizing at a different contentsScale.
|
||||||
|
* Read this property if you need to know the future contentsScale of your layer, eg in drawParameters.
|
||||||
|
*
|
||||||
|
* @see setNeedsDisplayAtScale:
|
||||||
|
*/
|
||||||
|
@property (nonatomic, assign, readonly) CGFloat contentsScaleForDisplay;
|
||||||
|
|
||||||
|
|
||||||
/** @name Touch handling */
|
/** @name Touch handling */
|
||||||
|
|
||||||
@@ -363,38 +389,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
*/
|
*/
|
||||||
- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event;
|
- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event;
|
||||||
|
|
||||||
|
|
||||||
/** @name Observing node-related changes */
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called just before the view is added to a window.
|
|
||||||
*/
|
|
||||||
- (void)willEnterHierarchy ASDISPLAYNODE_REQUIRES_SUPER;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called after the view is removed from the window.
|
|
||||||
*/
|
|
||||||
- (void)didExitHierarchy ASDISPLAYNODE_REQUIRES_SUPER;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides an opportunity to clear backing store and other memory-intensive intermediates, such as text layout managers
|
|
||||||
* on the current node.
|
|
||||||
*
|
|
||||||
* @discussion Called by -recursivelyClearContents. Base class implements self.contents = nil, clearing any backing
|
|
||||||
* store, for asynchronous regeneration when needed.
|
|
||||||
*/
|
|
||||||
- (void)clearContents ASDISPLAYNODE_REQUIRES_SUPER;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides an opportunity to clear any fetched data (e.g. remote / network or database-queried) on the current node.
|
|
||||||
*
|
|
||||||
* @discussion This will not clear data recursively for all subnodes. Either call -recursivelyClearFetchedData or
|
|
||||||
* selectively clear fetched data.
|
|
||||||
*/
|
|
||||||
- (void)clearFetchedData ASDISPLAYNODE_REQUIRES_SUPER;
|
|
||||||
|
|
||||||
|
|
||||||
/** @name Placeholders */
|
/** @name Placeholders */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -414,6 +408,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
*/
|
*/
|
||||||
- (nullable UIImage *)placeholderImage;
|
- (nullable UIImage *)placeholderImage;
|
||||||
|
|
||||||
|
|
||||||
/** @name Description */
|
/** @name Description */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1470,9 +1470,9 @@ static NSInteger incrementIfFound(NSInteger i) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Helper method to summarize whether or not the node run through the display process
|
// Helper method to summarize whether or not the node run through the display process
|
||||||
- (BOOL)_implementsDisplay
|
- (BOOL)__implementsDisplay
|
||||||
{
|
{
|
||||||
return _flags.implementsDrawRect == YES || _flags.implementsImageDisplay == YES;
|
return _flags.implementsDrawRect == YES || _flags.implementsImageDisplay == YES || self.shouldRasterizeDescendants;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_setupPlaceholderLayer
|
- (void)_setupPlaceholderLayer
|
||||||
@@ -1502,7 +1502,7 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
|
|||||||
// (even a runloop observer at a late call order will not stop the next frame from compositing, showing placeholders).
|
// (even a runloop observer at a late call order will not stop the next frame from compositing, showing placeholders).
|
||||||
|
|
||||||
ASDisplayNode *node = [layer asyncdisplaykit_node];
|
ASDisplayNode *node = [layer asyncdisplaykit_node];
|
||||||
if (!layer.contents && [node _implementsDisplay]) {
|
if (!layer.contents && [node __implementsDisplay]) {
|
||||||
// For layers that do get displayed here, this immediately kicks off the work on the concurrent -[_ASDisplayLayer displayQueue].
|
// For layers that do get displayed here, this immediately kicks off the work on the concurrent -[_ASDisplayLayer displayQueue].
|
||||||
// At the same time, it creates an associated _ASAsyncTransaction, which we can use to block on display completion. See ASDisplayNode+AsyncDisplay.mm.
|
// At the same time, it creates an associated _ASAsyncTransaction, which we can use to block on display completion. See ASDisplayNode+AsyncDisplay.mm.
|
||||||
[layer displayIfNeeded];
|
[layer displayIfNeeded];
|
||||||
@@ -1722,6 +1722,10 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
|
|||||||
[self clearFetchedData];
|
[self clearFetchedData];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)visibilityDidChange:(BOOL)isVisible
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We currently only set interface state on nodes in table/collection views. For other nodes, if they are
|
* We currently only set interface state on nodes in table/collection views. For other nodes, if they are
|
||||||
* in the hierarchy we enable all ASInterfaceState types with `ASInterfaceStateInHierarchy`, otherwise `None`.
|
* in the hierarchy we enable all ASInterfaceState types with `ASInterfaceStateInHierarchy`, otherwise `None`.
|
||||||
@@ -1776,11 +1780,17 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
|
|||||||
// Entered or exited data loading state.
|
// Entered or exited data loading state.
|
||||||
if ((newState & ASInterfaceStateVisible) != (oldState & ASInterfaceStateVisible)) {
|
if ((newState & ASInterfaceStateVisible) != (oldState & ASInterfaceStateVisible)) {
|
||||||
if (newState & ASInterfaceStateVisible) {
|
if (newState & ASInterfaceStateVisible) {
|
||||||
// Consider providing a -didBecomeVisible.
|
[self visibilityDidChange:YES];
|
||||||
} else {
|
} else {
|
||||||
// Consider providing a -didBecomeInvisible.
|
[self visibilityDidChange:NO];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[self interfaceStateDidChange:newState fromState:oldState];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)interfaceStateDidChange:(ASInterfaceState)newState fromState:(ASInterfaceState)oldState
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)enterInterfaceState:(ASInterfaceState)interfaceState
|
- (void)enterInterfaceState:(ASInterfaceState)interfaceState
|
||||||
@@ -2138,7 +2148,7 @@ static void _recursivelySetDisplaySuspended(ASDisplayNode *node, CALayer *layer,
|
|||||||
|
|
||||||
self.asyncLayer.displaySuspended = flag;
|
self.asyncLayer.displaySuspended = flag;
|
||||||
|
|
||||||
if ([self _implementsDisplay]) {
|
if ([self __implementsDisplay]) {
|
||||||
if (flag) {
|
if (flag) {
|
||||||
[_supernode subnodeDisplayDidFinish:self];
|
[_supernode subnodeDisplayDidFinish:self];
|
||||||
} else {
|
} else {
|
||||||
@@ -2307,7 +2317,6 @@ static void _recursivelySetDisplaySuspended(ASDisplayNode *node, CALayer *layer,
|
|||||||
static const char *ASDisplayNodeAssociatedNodeKey = "ASAssociatedNode";
|
static const char *ASDisplayNodeAssociatedNodeKey = "ASAssociatedNode";
|
||||||
|
|
||||||
@implementation UIView (ASDisplayNodeInternal)
|
@implementation UIView (ASDisplayNodeInternal)
|
||||||
@dynamic asyncdisplaykit_node;
|
|
||||||
|
|
||||||
- (void)setAsyncdisplaykit_node:(ASDisplayNode *)node
|
- (void)setAsyncdisplaykit_node:(ASDisplayNode *)node
|
||||||
{
|
{
|
||||||
@@ -2316,16 +2325,24 @@ static const char *ASDisplayNodeAssociatedNodeKey = "ASAssociatedNode";
|
|||||||
|
|
||||||
- (ASDisplayNode *)asyncdisplaykit_node
|
- (ASDisplayNode *)asyncdisplaykit_node
|
||||||
{
|
{
|
||||||
ASDisplayNode *node = objc_getAssociatedObject(self, ASDisplayNodeAssociatedNodeKey);
|
return objc_getAssociatedObject(self, ASDisplayNodeAssociatedNodeKey);
|
||||||
return node;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation CALayer (ASDisplayNodeInternal)
|
@implementation CALayer (ASDisplayNodeInternal)
|
||||||
@dynamic asyncdisplaykit_node;
|
|
||||||
@end
|
|
||||||
|
|
||||||
|
- (void)setAsyncdisplaykit_node:(ASDisplayNode *)node
|
||||||
|
{
|
||||||
|
objc_setAssociatedObject(self, ASDisplayNodeAssociatedNodeKey, node, OBJC_ASSOCIATION_ASSIGN); // Weak reference to avoid cycle, since the node retains the layer.
|
||||||
|
}
|
||||||
|
|
||||||
|
- (ASDisplayNode *)asyncdisplaykit_node
|
||||||
|
{
|
||||||
|
return objc_getAssociatedObject(self, ASDisplayNodeAssociatedNodeKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
@implementation UIView (AsyncDisplayKit)
|
@implementation UIView (AsyncDisplayKit)
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
@interface ASMapNode : ASImageNode
|
@interface ASMapNode : ASImageNode
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The current region of ASMapNode. This can be set at any time and ASMapNode will animate the change.
|
The current region of ASMapNode. This can be set at any time and ASMapNode will animate the change. This property may be set from a background thread before the node is loaded, and will automatically be applied to define the region of the static snapshot (if .liveMap = NO) or the internal MKMapView (otherwise).
|
||||||
*/
|
*/
|
||||||
@property (nonatomic, assign) MKCoordinateRegion region;
|
@property (nonatomic, assign) MKCoordinateRegion region;
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
@property (nullable, nonatomic, readonly) MKMapView *mapView;
|
@property (nullable, nonatomic, readonly) MKMapView *mapView;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Set this to YES to turn the snapshot into an interactive MKMapView and vice versa. Defaults to NO.
|
Set this to YES to turn the snapshot into an interactive MKMapView and vice versa. Defaults to NO. This property may be set on a background thread before the node is loaded, and will automatically be actioned, once the node is loaded.
|
||||||
*/
|
*/
|
||||||
@property (nonatomic, assign, getter=isLiveMap) BOOL liveMap;
|
@property (nonatomic, assign, getter=isLiveMap) BOOL liveMap;
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
@synthesize needsMapReloadOnBoundsChange = _needsMapReloadOnBoundsChange;
|
@synthesize needsMapReloadOnBoundsChange = _needsMapReloadOnBoundsChange;
|
||||||
@synthesize mapDelegate = _mapDelegate;
|
@synthesize mapDelegate = _mapDelegate;
|
||||||
@synthesize region = _region;
|
@synthesize region = _region;
|
||||||
|
@synthesize liveMap = _liveMap;
|
||||||
|
|
||||||
#pragma mark - Lifecycle
|
#pragma mark - Lifecycle
|
||||||
- (instancetype)init
|
- (instancetype)init
|
||||||
@@ -37,9 +38,11 @@
|
|||||||
self.clipsToBounds = YES;
|
self.clipsToBounds = YES;
|
||||||
|
|
||||||
_needsMapReloadOnBoundsChange = YES;
|
_needsMapReloadOnBoundsChange = YES;
|
||||||
|
_liveMap = NO;
|
||||||
_centerCoordinateOfMap = kCLLocationCoordinate2DInvalid;
|
_centerCoordinateOfMap = kCLLocationCoordinate2DInvalid;
|
||||||
_region = MKCoordinateRegionMake(CLLocationCoordinate2DMake(43.432858, 13.183671), MKCoordinateSpanMake(0.2, 0.2));
|
|
||||||
|
//Default world-scale view
|
||||||
|
_region = MKCoordinateRegionForMapRect(MKMapRectWorld);
|
||||||
|
|
||||||
_options = [[MKMapSnapshotOptions alloc] init];
|
_options = [[MKMapSnapshotOptions alloc] init];
|
||||||
_options.region = _region;
|
_options.region = _region;
|
||||||
@@ -50,26 +53,31 @@
|
|||||||
- (void)didLoad
|
- (void)didLoad
|
||||||
{
|
{
|
||||||
[super didLoad];
|
[super didLoad];
|
||||||
if ([self wasLiveMapPreviously]) {
|
if (self.isLiveMap) {
|
||||||
self.userInteractionEnabled = YES;
|
self.userInteractionEnabled = YES;
|
||||||
[self addLiveMap];
|
[self addLiveMap];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setLayerBacked:(BOOL)layerBacked
|
||||||
|
{
|
||||||
|
ASDisplayNodeAssert(!self.isLiveMap, @"ASMapNode can not be layer backed whilst .liveMap = YES, set .liveMap = NO to use layer backing.");
|
||||||
|
[super setLayerBacked:layerBacked];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)fetchData
|
- (void)fetchData
|
||||||
{
|
{
|
||||||
[super fetchData];
|
[super fetchData];
|
||||||
if ([self wasLiveMapPreviously]) {
|
if (self.isLiveMap) {
|
||||||
[self addLiveMap];
|
[self addLiveMap];
|
||||||
} else {
|
} else {
|
||||||
[self setUpSnapshotter];
|
|
||||||
[self takeSnapshot];
|
[self takeSnapshot];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)clearFetchedData
|
- (void)clearContents
|
||||||
{
|
{
|
||||||
[super clearFetchedData];
|
[super clearContents];
|
||||||
if (self.isLiveMap) {
|
if (self.isLiveMap) {
|
||||||
[self removeLiveMap];
|
[self removeLiveMap];
|
||||||
}
|
}
|
||||||
@@ -79,17 +87,21 @@
|
|||||||
|
|
||||||
- (BOOL)isLiveMap
|
- (BOOL)isLiveMap
|
||||||
{
|
{
|
||||||
return (_mapView != nil);
|
ASDN::MutexLocker l(_propertyLock);
|
||||||
|
return _liveMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setLiveMap:(BOOL)liveMap
|
- (void)setLiveMap:(BOOL)liveMap
|
||||||
{
|
{
|
||||||
liveMap ? [self addLiveMap] : [self removeLiveMap];
|
ASDisplayNodeAssert(!self.isLayerBacked, @"ASMapNode can not use the interactive map feature whilst .isLayerBacked = YES, set .layerBacked = NO to use the interactive map feature.");
|
||||||
}
|
ASDN::MutexLocker l(_propertyLock);
|
||||||
|
if (liveMap == _liveMap) {
|
||||||
- (BOOL)wasLiveMapPreviously
|
return;
|
||||||
{
|
}
|
||||||
return CLLocationCoordinate2DIsValid(_centerCoordinateOfMap);
|
_liveMap = liveMap;
|
||||||
|
if (self.nodeLoaded) {
|
||||||
|
liveMap ? [self addLiveMap] : [self removeLiveMap];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)needsMapReloadOnBoundsChange
|
- (BOOL)needsMapReloadOnBoundsChange
|
||||||
@@ -127,63 +139,62 @@
|
|||||||
|
|
||||||
- (void)takeSnapshot
|
- (void)takeSnapshot
|
||||||
{
|
{
|
||||||
if (!_snapshotter.isLoading) {
|
if (!_snapshotter) {
|
||||||
[_snapshotter startWithCompletionHandler:^(MKMapSnapshot *snapshot, NSError *error) {
|
[self setUpSnapshotter];
|
||||||
if (!error) {
|
}
|
||||||
UIImage *image = snapshot.image;
|
[_snapshotter cancel];
|
||||||
CGRect finalImageRect = CGRectMake(0, 0, image.size.width, image.size.height);
|
[_snapshotter startWithCompletionHandler:^(MKMapSnapshot *snapshot, NSError *error) {
|
||||||
|
if (!error) {
|
||||||
UIGraphicsBeginImageContextWithOptions(image.size, YES, image.scale);
|
UIImage *image = snapshot.image;
|
||||||
[image drawAtPoint:CGPointMake(0, 0)];
|
CGRect finalImageRect = CGRectMake(0, 0, image.size.width, image.size.height);
|
||||||
|
|
||||||
if (_annotations.count > 0 ) {
|
UIGraphicsBeginImageContextWithOptions(image.size, YES, image.scale);
|
||||||
// Get a standard annotation view pin. Future implementations should use a custom annotation image property.
|
[image drawAtPoint:CGPointMake(0, 0)];
|
||||||
MKAnnotationView *pin = [[MKPinAnnotationView alloc] initWithAnnotation:nil reuseIdentifier:@""];
|
|
||||||
UIImage *pinImage = pin.image;
|
if (_annotations.count > 0 ) {
|
||||||
for (id<MKAnnotation>annotation in _annotations)
|
// Get a standard annotation view pin. Future implementations should use a custom annotation image property.
|
||||||
|
MKAnnotationView *pin = [[MKPinAnnotationView alloc] initWithAnnotation:nil reuseIdentifier:@""];
|
||||||
|
UIImage *pinImage = pin.image;
|
||||||
|
for (id<MKAnnotation>annotation in _annotations)
|
||||||
|
{
|
||||||
|
CGPoint point = [snapshot pointForCoordinate:annotation.coordinate];
|
||||||
|
if (CGRectContainsPoint(finalImageRect, point))
|
||||||
{
|
{
|
||||||
CGPoint point = [snapshot pointForCoordinate:annotation.coordinate];
|
CGPoint pinCenterOffset = pin.centerOffset;
|
||||||
if (CGRectContainsPoint(finalImageRect, point))
|
point.x -= pin.bounds.size.width / 2.0;
|
||||||
{
|
point.y -= pin.bounds.size.height / 2.0;
|
||||||
CGPoint pinCenterOffset = pin.centerOffset;
|
point.x += pinCenterOffset.x;
|
||||||
point.x -= pin.bounds.size.width / 2.0;
|
point.y += pinCenterOffset.y;
|
||||||
point.y -= pin.bounds.size.height / 2.0;
|
[pinImage drawAtPoint:point];
|
||||||
point.x += pinCenterOffset.x;
|
|
||||||
point.y += pinCenterOffset.y;
|
|
||||||
[pinImage drawAtPoint:point];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext();
|
|
||||||
UIGraphicsEndImageContext();
|
|
||||||
self.image = finalImage;
|
|
||||||
}
|
}
|
||||||
}];
|
|
||||||
}
|
UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||||
|
UIGraphicsEndImageContext();
|
||||||
|
self.image = finalImage;
|
||||||
|
}
|
||||||
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setUpSnapshotter
|
- (void)setUpSnapshotter
|
||||||
{
|
{
|
||||||
if (!_snapshotter) {
|
ASDisplayNodeAssert(!CGSizeEqualToSize(CGSizeZero, self.calculatedSize), @"self.calculatedSize can not be zero. Make sure that you are setting a preferredFrameSize or wrapping ASMapNode in a ASRatioLayoutSpec or similar.");
|
||||||
ASDisplayNodeAssert(!CGSizeEqualToSize(CGSizeZero, self.calculatedSize), @"self.calculatedSize can not be zero. Make sure that you are setting a preferredFrameSize or wrapping ASMapNode in a ASRatioLayoutSpec or similar.");
|
_options.size = self.calculatedSize;
|
||||||
_options.size = self.calculatedSize;
|
_snapshotter = [[MKMapSnapshotter alloc] initWithOptions:_options];
|
||||||
_snapshotter = [[MKMapSnapshotter alloc] initWithOptions:_options];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)resetSnapshotter
|
- (void)resetSnapshotter
|
||||||
{
|
{
|
||||||
if (!_snapshotter.isLoading) {
|
[_snapshotter cancel];
|
||||||
_snapshotter = [[MKMapSnapshotter alloc] initWithOptions:_options];
|
_snapshotter = [[MKMapSnapshotter alloc] initWithOptions:_options];
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Actions
|
#pragma mark - Actions
|
||||||
- (void)addLiveMap
|
- (void)addLiveMap
|
||||||
{
|
{
|
||||||
ASDisplayNodeAssertMainThread();
|
ASDisplayNodeAssertMainThread();
|
||||||
if (!self.isLiveMap) {
|
if (!_mapView) {
|
||||||
__weak ASMapNode *weakSelf = self;
|
__weak ASMapNode *weakSelf = self;
|
||||||
_mapView = [[MKMapView alloc] initWithFrame:CGRectZero];
|
_mapView = [[MKMapView alloc] initWithFrame:CGRectZero];
|
||||||
_mapView.delegate = weakSelf.mapDelegate;
|
_mapView.delegate = weakSelf.mapDelegate;
|
||||||
@@ -194,8 +205,6 @@
|
|||||||
|
|
||||||
if (CLLocationCoordinate2DIsValid(_centerCoordinateOfMap)) {
|
if (CLLocationCoordinate2DIsValid(_centerCoordinateOfMap)) {
|
||||||
[_mapView setCenterCoordinate:_centerCoordinateOfMap];
|
[_mapView setCenterCoordinate:_centerCoordinateOfMap];
|
||||||
} else {
|
|
||||||
_centerCoordinateOfMap = _options.region.center;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,20 +8,35 @@
|
|||||||
|
|
||||||
#import <AsyncDisplayKit/ASCollectionNode.h>
|
#import <AsyncDisplayKit/ASCollectionNode.h>
|
||||||
|
|
||||||
@protocol ASPagerNodeDataSource;
|
@class ASPagerNode;
|
||||||
|
@protocol ASPagerNodeDataSource <NSObject>
|
||||||
|
// This method replaces -collectionView:numberOfItemsInSection:
|
||||||
|
- (NSInteger)numberOfPagesInPagerNode:(ASPagerNode *)pagerNode;
|
||||||
|
|
||||||
|
// This method replaces -collectionView:nodeForItemAtIndexPath:
|
||||||
|
- (ASCellNode *)pagerNode:(ASPagerNode *)pagerNode nodeAtIndex:(NSInteger)index;
|
||||||
|
@end
|
||||||
|
|
||||||
@interface ASPagerNode : ASCollectionNode
|
@interface ASPagerNode : ASCollectionNode
|
||||||
|
|
||||||
@property (weak, nonatomic) id<ASPagerNodeDataSource> dataSource;
|
// Configures a default horizontal, paging flow layout with 0 inter-item spacing.
|
||||||
|
- (instancetype)init;
|
||||||
|
|
||||||
|
// Initializer with custom-configured flow layout properties.
|
||||||
|
- (instancetype)initWithFlowLayout:(UICollectionViewFlowLayout *)flowLayout;
|
||||||
|
|
||||||
|
// The underlying ASCollectionView object.
|
||||||
|
- (ASCollectionView *)collectionView;
|
||||||
|
|
||||||
|
// Delegate is optional, and uses the same protocol as ASCollectionNode.
|
||||||
|
// This includes UIScrollViewDelegate as well as most methods from UICollectionViewDelegate, like willDisplay...
|
||||||
|
@property (weak, nonatomic) id <ASCollectionDelegate> delegate;
|
||||||
|
|
||||||
|
// Data Source is required, and uses a different protocol from ASCollectionNode.
|
||||||
|
- (void)setDataSource:(id <ASPagerNodeDataSource>)dataSource;
|
||||||
|
- (id <ASPagerNodeDataSource>)dataSource;
|
||||||
|
|
||||||
- (void)scrollToPageAtIndex:(NSInteger)index animated:(BOOL)animated;
|
- (void)scrollToPageAtIndex:(NSInteger)index animated:(BOOL)animated;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@protocol ASPagerNodeDataSource <NSObject>
|
|
||||||
|
|
||||||
- (NSInteger)numberOfPagesInPagerNode:(ASPagerNode *)pagerNode;
|
|
||||||
|
|
||||||
- (ASCellNode *)pagerNode:(ASPagerNode *)pagerNode nodeAtIndex:(NSInteger)index;
|
|
||||||
|
|
||||||
@end
|
|
||||||
@@ -7,41 +7,77 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import "ASPagerNode.h"
|
#import "ASPagerNode.h"
|
||||||
|
#import "ASDelegateProxy.h"
|
||||||
|
|
||||||
#import <AsyncDisplayKit/AsyncDisplayKit.h>
|
#import <AsyncDisplayKit/AsyncDisplayKit.h>
|
||||||
|
|
||||||
@interface ASPagerNode () <ASCollectionViewDataSource, ASCollectionViewDelegateFlowLayout> {
|
@interface ASPagerNode () <ASCollectionDataSource, ASCollectionViewDelegateFlowLayout, ASDelegateProxyInterceptor> {
|
||||||
UICollectionViewFlowLayout *_flowLayout;
|
UICollectionViewFlowLayout *_flowLayout;
|
||||||
|
ASPagerNodeProxy *_proxy;
|
||||||
|
id <ASPagerNodeDataSource> _pagerDataSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation ASPagerNode
|
@implementation ASPagerNode
|
||||||
|
@dynamic delegate;
|
||||||
|
|
||||||
- (instancetype)init
|
- (instancetype)init
|
||||||
{
|
{
|
||||||
_flowLayout = [[UICollectionViewFlowLayout alloc] init];
|
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
|
||||||
_flowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
|
flowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
|
||||||
_flowLayout.minimumInteritemSpacing = 0;
|
flowLayout.minimumInteritemSpacing = 0;
|
||||||
_flowLayout.minimumLineSpacing = 0;
|
flowLayout.minimumLineSpacing = 0;
|
||||||
|
|
||||||
self = [super initWithCollectionViewLayout:_flowLayout];
|
return [self initWithFlowLayout:flowLayout];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)initWithFlowLayout:(UICollectionViewFlowLayout *)flowLayout
|
||||||
|
{
|
||||||
|
self = [super initWithCollectionViewLayout:flowLayout];
|
||||||
if (self != nil) {
|
if (self != nil) {
|
||||||
|
_flowLayout = flowLayout;
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (ASCollectionView *)collectionView
|
||||||
|
{
|
||||||
|
return self.view;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setDataSource:(id <ASPagerNodeDataSource>)pagerDataSource
|
||||||
|
{
|
||||||
|
if (pagerDataSource != _pagerDataSource) {
|
||||||
|
_pagerDataSource = pagerDataSource;
|
||||||
|
_proxy = pagerDataSource ? [[ASPagerNodeProxy alloc] initWithTarget:pagerDataSource interceptor:self] : nil;
|
||||||
|
super.dataSource = (id <ASCollectionDataSource>)_proxy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)proxyTargetHasDeallocated:(ASDelegateProxy *)proxy
|
||||||
|
{
|
||||||
|
[self setDataSource:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id <ASPagerNodeDataSource>)dataSource
|
||||||
|
{
|
||||||
|
return _pagerDataSource;
|
||||||
|
}
|
||||||
|
|
||||||
- (void)didLoad
|
- (void)didLoad
|
||||||
{
|
{
|
||||||
[super didLoad];
|
[super didLoad];
|
||||||
|
|
||||||
self.view.asyncDataSource = self;
|
ASCollectionView *cv = self.view;
|
||||||
self.view.asyncDelegate = self;
|
cv.asyncDataSource = self;
|
||||||
|
cv.asyncDelegate = self;
|
||||||
|
|
||||||
self.view.pagingEnabled = YES;
|
cv.pagingEnabled = YES;
|
||||||
self.view.allowsSelection = NO;
|
cv.allowsSelection = NO;
|
||||||
self.view.showsVerticalScrollIndicator = NO;
|
cv.showsVerticalScrollIndicator = NO;
|
||||||
self.view.showsHorizontalScrollIndicator = NO;
|
cv.showsHorizontalScrollIndicator = NO;
|
||||||
|
cv.scrollsToTop = NO;
|
||||||
|
|
||||||
ASRangeTuningParameters preloadParams = { .leadingBufferScreenfuls = 2.0, .trailingBufferScreenfuls = 2.0 };
|
ASRangeTuningParameters preloadParams = { .leadingBufferScreenfuls = 2.0, .trailingBufferScreenfuls = 2.0 };
|
||||||
ASRangeTuningParameters renderParams = { .leadingBufferScreenfuls = 1.0, .trailingBufferScreenfuls = 1.0 };
|
ASRangeTuningParameters renderParams = { .leadingBufferScreenfuls = 1.0, .trailingBufferScreenfuls = 1.0 };
|
||||||
@@ -61,14 +97,14 @@
|
|||||||
|
|
||||||
- (ASCellNode *)collectionView:(ASCollectionView *)collectionView nodeForItemAtIndexPath:(NSIndexPath *)indexPath
|
- (ASCellNode *)collectionView:(ASCollectionView *)collectionView nodeForItemAtIndexPath:(NSIndexPath *)indexPath
|
||||||
{
|
{
|
||||||
ASDisplayNodeAssert(self.dataSource != nil, @"ASPagerNode must have a data source to load paging nodes");
|
ASDisplayNodeAssert(_pagerDataSource != nil, @"ASPagerNode must have a data source to load paging nodes");
|
||||||
return [self.dataSource pagerNode:self nodeAtIndex:indexPath.item];
|
return [_pagerDataSource pagerNode:self nodeAtIndex:indexPath.item];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
|
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
|
||||||
{
|
{
|
||||||
ASDisplayNodeAssert(self.dataSource != nil, @"ASPagerNode must have a data source to load paging nodes");
|
ASDisplayNodeAssert(_pagerDataSource != nil, @"ASPagerNode must have a data source to load paging nodes");
|
||||||
return [self.dataSource numberOfPagesInPagerNode:self];
|
return [_pagerDataSource numberOfPagesInPagerNode:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath
|
- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath
|
||||||
|
|||||||
@@ -14,8 +14,13 @@
|
|||||||
*/
|
*/
|
||||||
@interface ASTableNode : ASDisplayNode
|
@interface ASTableNode : ASDisplayNode
|
||||||
|
|
||||||
- (instancetype)initWithStyle:(UITableViewStyle)style NS_DESIGNATED_INITIALIZER;
|
- (instancetype)init; // UITableViewStylePlain
|
||||||
|
- (instancetype)initWithStyle:(UITableViewStyle)style;
|
||||||
|
|
||||||
@property (nonatomic, readonly) ASTableView *view;
|
@property (nonatomic, readonly) ASTableView *view;
|
||||||
|
|
||||||
|
// These properties can be set without triggering the view to be created, so it's fine to set them in -init.
|
||||||
|
@property (weak, nonatomic) id <ASTableDelegate> delegate;
|
||||||
|
@property (weak, nonatomic) id <ASTableDataSource> dataSource;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -8,18 +8,105 @@
|
|||||||
|
|
||||||
#import "ASTableNode.h"
|
#import "ASTableNode.h"
|
||||||
|
|
||||||
|
@interface _ASTablePendingState : NSObject
|
||||||
|
@property (weak, nonatomic) id <ASTableDelegate> delegate;
|
||||||
|
@property (weak, nonatomic) id <ASTableDataSource> dataSource;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation _ASTablePendingState
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface ASTableNode ()
|
||||||
|
@property (nonatomic) _ASTablePendingState *pendingState;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface ASTableView ()
|
||||||
|
- (instancetype)_initWithFrame:(CGRect)frame style:(UITableViewStyle)style dataControllerClass:(Class)dataControllerClass;
|
||||||
|
@end
|
||||||
|
|
||||||
@implementation ASTableNode
|
@implementation ASTableNode
|
||||||
|
|
||||||
- (instancetype)initWithStyle:(UITableViewStyle)style
|
- (instancetype)_initWithStyle:(UITableViewStyle)style dataControllerClass:(Class)dataControllerClass
|
||||||
{
|
{
|
||||||
if (self = [super initWithViewBlock:^UIView *{
|
if (self = [super initWithViewBlock:^UIView *{ return [[ASTableView alloc] _initWithFrame:CGRectZero
|
||||||
return [[ASTableView alloc] initWithFrame:CGRectZero style:style];
|
style:style
|
||||||
}]) {
|
dataControllerClass:dataControllerClass]; }]) {
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (instancetype)initWithStyle:(UITableViewStyle)style
|
||||||
|
{
|
||||||
|
return [self _initWithStyle:style dataControllerClass:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)init
|
||||||
|
{
|
||||||
|
return [self _initWithStyle:UITableViewStylePlain dataControllerClass:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)didLoad
|
||||||
|
{
|
||||||
|
[super didLoad];
|
||||||
|
|
||||||
|
if (_pendingState) {
|
||||||
|
_ASTablePendingState *pendingState = _pendingState;
|
||||||
|
self.pendingState = nil;
|
||||||
|
|
||||||
|
ASTableView *view = self.view;
|
||||||
|
view.asyncDelegate = pendingState.delegate;
|
||||||
|
view.asyncDataSource = pendingState.dataSource;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (_ASTablePendingState *)pendingState
|
||||||
|
{
|
||||||
|
if (!_pendingState && ![self isNodeLoaded]) {
|
||||||
|
self.pendingState = [[_ASTablePendingState alloc] init];
|
||||||
|
}
|
||||||
|
ASDisplayNodeAssert(![self isNodeLoaded] || !_pendingState, @"ASTableNode should not have a pendingState once it is loaded");
|
||||||
|
return _pendingState;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setDelegate:(id <ASTableDelegate>)delegate
|
||||||
|
{
|
||||||
|
if ([self pendingState]) {
|
||||||
|
_pendingState.delegate = delegate;
|
||||||
|
} else {
|
||||||
|
ASDisplayNodeAssert([self isNodeLoaded], @"ASTableNode should be loaded if pendingState doesn't exist");
|
||||||
|
self.view.asyncDelegate = delegate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id <ASTableDelegate>)delegate
|
||||||
|
{
|
||||||
|
if ([self pendingState]) {
|
||||||
|
return _pendingState.delegate;
|
||||||
|
} else {
|
||||||
|
return self.view.asyncDelegate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setDataSource:(id <ASTableDataSource>)dataSource
|
||||||
|
{
|
||||||
|
if ([self pendingState]) {
|
||||||
|
_pendingState.dataSource = dataSource;
|
||||||
|
} else {
|
||||||
|
ASDisplayNodeAssert([self isNodeLoaded], @"ASTableNode should be loaded if pendingState doesn't exist");
|
||||||
|
self.view.asyncDataSource = dataSource;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id <ASTableDataSource>)dataSource
|
||||||
|
{
|
||||||
|
if ([self pendingState]) {
|
||||||
|
return _pendingState.dataSource;
|
||||||
|
} else {
|
||||||
|
return self.view.asyncDataSource;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (ASTableView *)view
|
- (ASTableView *)view
|
||||||
{
|
{
|
||||||
return (ASTableView *)[super view];
|
return (ASTableView *)[super view];
|
||||||
|
|||||||
@@ -7,18 +7,16 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
#import <AsyncDisplayKit/ASRangeController.h>
|
#import <AsyncDisplayKit/ASRangeController.h>
|
||||||
#import <AsyncDisplayKit/ASTableViewProtocols.h>
|
#import <AsyncDisplayKit/ASTableViewProtocols.h>
|
||||||
#import <AsyncDisplayKit/ASBaseDefines.h>
|
#import <AsyncDisplayKit/ASBaseDefines.h>
|
||||||
#import <AsyncDisplayKit/ASBatchContext.h>
|
#import <AsyncDisplayKit/ASBatchContext.h>
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
@class ASCellNode;
|
@class ASCellNode;
|
||||||
@protocol ASTableViewDataSource;
|
@protocol ASTableDataSource;
|
||||||
@protocol ASTableViewDelegate;
|
@protocol ASTableDelegate;
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Node-based table view.
|
* Node-based table view.
|
||||||
@@ -28,8 +26,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
*/
|
*/
|
||||||
@interface ASTableView : UITableView
|
@interface ASTableView : UITableView
|
||||||
|
|
||||||
@property (nonatomic, weak) id<ASTableViewDelegate> asyncDelegate; // must not be nil
|
@property (nonatomic, weak) id<ASTableDelegate> asyncDelegate;
|
||||||
@property (nonatomic, weak) id<ASTableViewDataSource> asyncDataSource;
|
@property (nonatomic, weak) id<ASTableDataSource> asyncDataSource;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializer.
|
* Initializer.
|
||||||
@@ -281,7 +279,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
/**
|
/**
|
||||||
* This is a node-based UITableViewDataSource.
|
* This is a node-based UITableViewDataSource.
|
||||||
*/
|
*/
|
||||||
@protocol ASTableViewDataSource <ASCommonTableViewDataSource, NSObject>
|
@protocol ASTableDataSource <ASCommonTableViewDataSource, NSObject>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Similar to -tableView:cellForRowAtIndexPath:.
|
* Similar to -tableView:cellForRowAtIndexPath:.
|
||||||
@@ -318,6 +316,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@protocol ASTableViewDataSource <ASTableDataSource>
|
||||||
|
@end
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a node-based UITableViewDelegate.
|
* This is a node-based UITableViewDelegate.
|
||||||
@@ -325,7 +325,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
* Note that -tableView:heightForRowAtIndexPath: has been removed; instead, your custom ASCellNode subclasses are
|
* Note that -tableView:heightForRowAtIndexPath: has been removed; instead, your custom ASCellNode subclasses are
|
||||||
* responsible for deciding their preferred onscreen height in -calculateSizeThatFits:.
|
* responsible for deciding their preferred onscreen height in -calculateSizeThatFits:.
|
||||||
*/
|
*/
|
||||||
@protocol ASTableViewDelegate <ASCommonTableViewDelegate, NSObject>
|
@protocol ASTableDelegate <ASCommonTableViewDelegate, NSObject>
|
||||||
|
|
||||||
@optional
|
@optional
|
||||||
|
|
||||||
@@ -361,4 +361,9 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
NS_ASSUME_NONNULL_END
|
NS_ASSUME_NONNULL_END
|
||||||
|
=======
|
||||||
|
@protocol ASTableViewDelegate <ASTableDelegate>;
|
||||||
|
@end
|
||||||
|
>>>>>>> master
|
||||||
|
|||||||
@@ -8,103 +8,26 @@
|
|||||||
|
|
||||||
#import "ASTableView.h"
|
#import "ASTableView.h"
|
||||||
#import "ASTableViewInternal.h"
|
#import "ASTableViewInternal.h"
|
||||||
|
#import "ASTableNode.h"
|
||||||
|
|
||||||
#import "ASAssert.h"
|
#import "ASAssert.h"
|
||||||
#import "ASBatchFetching.h"
|
#import "ASBatchFetching.h"
|
||||||
#import "ASChangeSetDataController.h"
|
#import "ASChangeSetDataController.h"
|
||||||
#import "ASCollectionViewLayoutController.h"
|
#import "ASCollectionViewLayoutController.h"
|
||||||
|
#import "ASDelegateProxy.h"
|
||||||
#import "ASDisplayNode+FrameworkPrivate.h"
|
#import "ASDisplayNode+FrameworkPrivate.h"
|
||||||
#import "ASInternalHelpers.h"
|
#import "ASInternalHelpers.h"
|
||||||
#import "ASLayout.h"
|
#import "ASLayout.h"
|
||||||
#import "ASLayoutController.h"
|
#import "ASLayoutController.h"
|
||||||
#import "ASRangeController.h"
|
#import "ASRangeController.h"
|
||||||
|
|
||||||
|
#import <CoreFoundation/CoreFoundation.h>
|
||||||
|
|
||||||
static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
||||||
|
|
||||||
//#define LOG(...) NSLog(__VA_ARGS__)
|
//#define LOG(...) NSLog(__VA_ARGS__)
|
||||||
#define LOG(...)
|
#define LOG(...)
|
||||||
|
|
||||||
#pragma mark -
|
|
||||||
#pragma mark Proxying.
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ASTableView intercepts and/or overrides a few of UITableView's critical data source and delegate methods.
|
|
||||||
*
|
|
||||||
* Any selector included in this function *MUST* be implemented by ASTableView.
|
|
||||||
*/
|
|
||||||
static BOOL _isInterceptedSelector(SEL sel)
|
|
||||||
{
|
|
||||||
return (
|
|
||||||
// handled by ASTableView node<->cell machinery
|
|
||||||
sel == @selector(tableView:cellForRowAtIndexPath:) ||
|
|
||||||
sel == @selector(tableView:heightForRowAtIndexPath:) ||
|
|
||||||
|
|
||||||
// handled by ASRangeController
|
|
||||||
sel == @selector(numberOfSectionsInTableView:) ||
|
|
||||||
sel == @selector(tableView:numberOfRowsInSection:) ||
|
|
||||||
|
|
||||||
// used for ASRangeController visibility updates
|
|
||||||
sel == @selector(tableView:willDisplayCell:forRowAtIndexPath:) ||
|
|
||||||
sel == @selector(tableView:didEndDisplayingCell:forRowAtIndexPath:) ||
|
|
||||||
|
|
||||||
// used for batch fetching API
|
|
||||||
sel == @selector(scrollViewWillEndDragging:withVelocity:targetContentOffset:)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stand-in for UITableViewDataSource and UITableViewDelegate. Any method calls we intercept are routed to ASTableView;
|
|
||||||
* everything else leaves AsyncDisplayKit safely and arrives at the original intended data source and delegate.
|
|
||||||
*/
|
|
||||||
@interface _ASTableViewProxy : NSProxy
|
|
||||||
- (instancetype)initWithTarget:(id<NSObject>)target interceptor:(ASTableView *)interceptor;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation _ASTableViewProxy {
|
|
||||||
id<NSObject> __weak _target;
|
|
||||||
ASTableView * __weak _interceptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (instancetype)initWithTarget:(id<NSObject>)target interceptor:(ASTableView *)interceptor
|
|
||||||
{
|
|
||||||
// -[NSProxy init] is undefined
|
|
||||||
if (!self) {
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASDisplayNodeAssert(target, @"target must not be nil");
|
|
||||||
ASDisplayNodeAssert(interceptor, @"interceptor must not be nil");
|
|
||||||
|
|
||||||
_target = target;
|
|
||||||
_interceptor = interceptor;
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)respondsToSelector:(SEL)aSelector
|
|
||||||
{
|
|
||||||
ASDisplayNodeAssert(_target, @"target must not be nil"); // catch weak ref's being nilled early
|
|
||||||
ASDisplayNodeAssert(_interceptor, @"interceptor must not be nil");
|
|
||||||
|
|
||||||
return (_isInterceptedSelector(aSelector) || [_target respondsToSelector:aSelector]);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id)forwardingTargetForSelector:(SEL)aSelector
|
|
||||||
{
|
|
||||||
ASDisplayNodeAssert(_target, @"target must not be nil"); // catch weak ref's being nilled early
|
|
||||||
ASDisplayNodeAssert(_interceptor, @"interceptor must not be nil");
|
|
||||||
|
|
||||||
if (_isInterceptedSelector(aSelector)) {
|
|
||||||
return _interceptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
return [_target respondsToSelector:aSelector] ? _target : nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
#pragma mark ASCellNode<->UITableViewCell bridging.
|
#pragma mark ASCellNode<->UITableViewCell bridging.
|
||||||
|
|
||||||
@@ -156,13 +79,16 @@ static BOOL _isInterceptedSelector(SEL sel)
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
#pragma mark ASTableView
|
#pragma mark ASTableView
|
||||||
|
|
||||||
@interface ASTableView () <ASRangeControllerDataSource, ASRangeControllerDelegate, ASDataControllerSource, _ASTableViewCellDelegate, ASCellNodeLayoutDelegate> {
|
@interface ASTableNode ()
|
||||||
_ASTableViewProxy *_proxyDataSource;
|
- (instancetype)_initWithStyle:(UITableViewStyle)style dataControllerClass:(Class)dataControllerClass;
|
||||||
_ASTableViewProxy *_proxyDelegate;
|
@end
|
||||||
|
|
||||||
|
@interface ASTableView () <ASRangeControllerDataSource, ASRangeControllerDelegate, ASDataControllerSource, _ASTableViewCellDelegate, ASCellNodeLayoutDelegate, ASDelegateProxyInterceptor> {
|
||||||
|
ASTableViewProxy *_proxyDataSource;
|
||||||
|
ASTableViewProxy *_proxyDelegate;
|
||||||
|
|
||||||
ASFlowLayoutController *_layoutController;
|
ASFlowLayoutController *_layoutController;
|
||||||
|
|
||||||
@@ -180,6 +106,7 @@ static BOOL _isInterceptedSelector(SEL sel)
|
|||||||
CGFloat _nodesConstrainedWidth;
|
CGFloat _nodesConstrainedWidth;
|
||||||
BOOL _ignoreNodesConstrainedWidthChange;
|
BOOL _ignoreNodesConstrainedWidthChange;
|
||||||
BOOL _queuedNodeHeightUpdate;
|
BOOL _queuedNodeHeightUpdate;
|
||||||
|
BOOL _isDeallocating;
|
||||||
}
|
}
|
||||||
|
|
||||||
@property (atomic, assign) BOOL asyncDataSourceLocked;
|
@property (atomic, assign) BOOL asyncDataSourceLocked;
|
||||||
@@ -224,6 +151,12 @@ static BOOL _isInterceptedSelector(SEL sel)
|
|||||||
// If the initial size is 0, expect a size change very soon which is part of the initial configuration
|
// If the initial size is 0, expect a size change very soon which is part of the initial configuration
|
||||||
// and should not trigger a relayout.
|
// and should not trigger a relayout.
|
||||||
_ignoreNodesConstrainedWidthChange = (_nodesConstrainedWidth == 0);
|
_ignoreNodesConstrainedWidthChange = (_nodesConstrainedWidth == 0);
|
||||||
|
|
||||||
|
_proxyDelegate = [[ASTableViewProxy alloc] initWithTarget:nil interceptor:self];
|
||||||
|
super.delegate = (id<UITableViewDelegate>)_proxyDelegate;
|
||||||
|
|
||||||
|
_proxyDataSource = [[ASTableViewProxy alloc] initWithTarget:nil interceptor:self];
|
||||||
|
super.dataSource = (id<UITableViewDataSource>)_proxyDataSource;
|
||||||
|
|
||||||
[self registerClass:_ASTableViewCell.class forCellReuseIdentifier:kCellReuseIdentifier];
|
[self registerClass:_ASTableViewCell.class forCellReuseIdentifier:kCellReuseIdentifier];
|
||||||
}
|
}
|
||||||
@@ -233,41 +166,45 @@ static BOOL _isInterceptedSelector(SEL sel)
|
|||||||
return [self initWithFrame:frame style:style asyncDataFetching:NO];
|
return [self initWithFrame:frame style:style asyncDataFetching:NO];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: This method is deprecated and will probably be removed in or shortly after 2.0.
|
||||||
- (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style asyncDataFetching:(BOOL)asyncDataFetchingEnabled
|
- (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style asyncDataFetching:(BOOL)asyncDataFetchingEnabled
|
||||||
{
|
{
|
||||||
return [self initWithFrame:frame style:style dataControllerClass:[self.class dataControllerClass] asyncDataFetching:asyncDataFetchingEnabled];
|
return [self initWithFrame:frame style:style dataControllerClass:[self.class dataControllerClass] asyncDataFetching:asyncDataFetchingEnabled];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style dataControllerClass:(Class)dataControllerClass asyncDataFetching:(BOOL)asyncDataFetchingEnabled
|
- (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style dataControllerClass:(Class)dataControllerClass asyncDataFetching:(BOOL)asyncDataFetchingEnabled
|
||||||
|
{
|
||||||
|
// ASTableNode *tableNode = [[ASTableNode alloc] _initWithStyle:style dataControllerClass:dataControllerClass];
|
||||||
|
// tableNode.frame = frame;
|
||||||
|
// return tableNode.view;
|
||||||
|
return [self _initWithFrame:frame style:style dataControllerClass:dataControllerClass];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)_initWithFrame:(CGRect)frame style:(UITableViewStyle)style dataControllerClass:(Class)dataControllerClass
|
||||||
{
|
{
|
||||||
if (!(self = [super initWithFrame:frame style:style]))
|
if (!(self = [super initWithFrame:frame style:style]))
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
// FIXME: asyncDataFetching is currently unreliable for some use cases.
|
|
||||||
// https://github.com/facebook/AsyncDisplayKit/issues/385
|
|
||||||
asyncDataFetchingEnabled = NO;
|
|
||||||
|
|
||||||
[self configureWithDataControllerClass:dataControllerClass asyncDataFetching:asyncDataFetchingEnabled];
|
if (!dataControllerClass) {
|
||||||
|
dataControllerClass = [self.class dataControllerClass];
|
||||||
|
}
|
||||||
|
[self configureWithDataControllerClass:dataControllerClass asyncDataFetching:NO];
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder
|
- (instancetype)initWithCoder:(NSCoder *)aDecoder
|
||||||
{
|
{
|
||||||
if (!(self = [super initWithCoder:aDecoder]))
|
NSLog(@"Warning: AsyncDisplayKit is not designed to be used with Interface Builder. Table properties set in IB will be lost.");
|
||||||
return nil;
|
return [self initWithFrame:CGRectZero style:UITableViewStylePlain];
|
||||||
|
|
||||||
[self configureWithDataControllerClass:[self.class dataControllerClass] asyncDataFetching:NO];
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)dealloc
|
- (void)dealloc
|
||||||
{
|
{
|
||||||
// Sometimes the UIKit classes can call back to their delegate even during deallocation.
|
// Sometimes the UIKit classes can call back to their delegate even during deallocation.
|
||||||
// This bug might be iOS 7-specific.
|
_isDeallocating = YES;
|
||||||
super.delegate = nil;
|
[self setAsyncDelegate:nil];
|
||||||
super.dataSource = nil;
|
[self setAsyncDataSource:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
@@ -290,17 +227,19 @@ static BOOL _isInterceptedSelector(SEL sel)
|
|||||||
// Note: It's common to check if the value hasn't changed and short-circuit but we aren't doing that here to handle
|
// Note: It's common to check if the value hasn't changed and short-circuit but we aren't doing that here to handle
|
||||||
// the (common) case of nilling the asyncDataSource in the ViewController's dealloc. In this case our _asyncDataSource
|
// the (common) case of nilling the asyncDataSource in the ViewController's dealloc. In this case our _asyncDataSource
|
||||||
// will return as nil (ARC magic) even though the _proxyDataSource still exists. It's really important to nil out
|
// will return as nil (ARC magic) even though the _proxyDataSource still exists. It's really important to nil out
|
||||||
// super.dataSource in this case because calls to _ASTableViewProxy will start failing and cause crashes.
|
// super.dataSource in this case because calls to ASTableViewProxy will start failing and cause crashes.
|
||||||
|
|
||||||
|
super.dataSource = nil;
|
||||||
|
|
||||||
if (asyncDataSource == nil) {
|
if (asyncDataSource == nil) {
|
||||||
super.dataSource = nil;
|
|
||||||
_asyncDataSource = nil;
|
_asyncDataSource = nil;
|
||||||
_proxyDataSource = nil;
|
_proxyDataSource = _isDeallocating ? nil : [[ASTableViewProxy alloc] initWithTarget:nil interceptor:self];
|
||||||
} else {
|
} else {
|
||||||
_asyncDataSource = asyncDataSource;
|
_asyncDataSource = asyncDataSource;
|
||||||
_proxyDataSource = [[_ASTableViewProxy alloc] initWithTarget:_asyncDataSource interceptor:self];
|
_proxyDataSource = [[ASTableViewProxy alloc] initWithTarget:_asyncDataSource interceptor:self];
|
||||||
super.dataSource = (id<UITableViewDataSource>)_proxyDataSource;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
super.dataSource = (id<UITableViewDataSource>)_proxyDataSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setAsyncDelegate:(id<ASTableViewDelegate>)asyncDelegate
|
- (void)setAsyncDelegate:(id<ASTableViewDelegate>)asyncDelegate
|
||||||
@@ -308,18 +247,30 @@ static BOOL _isInterceptedSelector(SEL sel)
|
|||||||
// Note: It's common to check if the value hasn't changed and short-circuit but we aren't doing that here to handle
|
// Note: It's common to check if the value hasn't changed and short-circuit but we aren't doing that here to handle
|
||||||
// the (common) case of nilling the asyncDelegate in the ViewController's dealloc. In this case our _asyncDelegate
|
// the (common) case of nilling the asyncDelegate in the ViewController's dealloc. In this case our _asyncDelegate
|
||||||
// will return as nil (ARC magic) even though the _proxyDelegate still exists. It's really important to nil out
|
// will return as nil (ARC magic) even though the _proxyDelegate still exists. It's really important to nil out
|
||||||
// super.delegate in this case because calls to _ASTableViewProxy will start failing and cause crashes.
|
// super.delegate in this case because calls to ASTableViewProxy will start failing and cause crashes.
|
||||||
|
|
||||||
|
// Order is important here, the asyncDelegate must be callable while nilling super.delegate to avoid random crashes
|
||||||
|
// in UIScrollViewAccessibility.
|
||||||
|
|
||||||
|
super.delegate = nil;
|
||||||
|
|
||||||
if (asyncDelegate == nil) {
|
if (asyncDelegate == nil) {
|
||||||
// order is important here, the delegate must be callable while nilling super.delegate to avoid random crashes
|
|
||||||
// in UIScrollViewAccessibility.
|
|
||||||
super.delegate = nil;
|
|
||||||
_asyncDelegate = nil;
|
_asyncDelegate = nil;
|
||||||
_proxyDelegate = nil;
|
_proxyDelegate = _isDeallocating ? nil : [[ASTableViewProxy alloc] initWithTarget:nil interceptor:self];
|
||||||
} else {
|
} else {
|
||||||
_asyncDelegate = asyncDelegate;
|
_asyncDelegate = asyncDelegate;
|
||||||
_proxyDelegate = [[_ASTableViewProxy alloc] initWithTarget:asyncDelegate interceptor:self];
|
_proxyDelegate = [[ASTableViewProxy alloc] initWithTarget:_asyncDelegate interceptor:self];
|
||||||
super.delegate = (id<UITableViewDelegate>)_proxyDelegate;
|
}
|
||||||
|
|
||||||
|
super.delegate = (id<UITableViewDelegate>)_proxyDelegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)proxyTargetHasDeallocated:(ASDelegateProxy *)proxy
|
||||||
|
{
|
||||||
|
if (proxy == _proxyDelegate) {
|
||||||
|
[self setAsyncDelegate:nil];
|
||||||
|
} else if (proxy == _proxyDataSource) {
|
||||||
|
[self setAsyncDataSource:nil];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,6 +62,15 @@ static NSString *ASTextNodeTruncationTokenAttributeName = @"ASTextNodeTruncation
|
|||||||
- (void)dealloc
|
- (void)dealloc
|
||||||
{
|
{
|
||||||
CGColorRelease(_backgroundColor);
|
CGColorRelease(_backgroundColor);
|
||||||
|
|
||||||
|
// Destruction of the layout managers/containers/text storage is quite
|
||||||
|
// expensive, and can take some time, so we dispatch onto a bg queue to
|
||||||
|
// actually dealloc.
|
||||||
|
__block ASTextKitRenderer *renderer = _renderer;
|
||||||
|
ASPerformBlockOnBackgroundThread(^{
|
||||||
|
renderer = nil;
|
||||||
|
});
|
||||||
|
_renderer = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -97,6 +106,8 @@ static NSString *ASTextNodeTruncationTokenAttributeName = @"ASTextNodeTruncation
|
|||||||
|
|
||||||
#pragma mark - NSObject
|
#pragma mark - NSObject
|
||||||
|
|
||||||
|
static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
||||||
|
|
||||||
- (instancetype)init
|
- (instancetype)init
|
||||||
{
|
{
|
||||||
if (self = [super init]) {
|
if (self = [super init]) {
|
||||||
@@ -120,7 +131,7 @@ static NSString *ASTextNodeTruncationTokenAttributeName = @"ASTextNodeTruncation
|
|||||||
self.opaque = NO;
|
self.opaque = NO;
|
||||||
self.backgroundColor = [UIColor clearColor];
|
self.backgroundColor = [UIColor clearColor];
|
||||||
|
|
||||||
self.linkAttributeNames = @[ NSLinkAttributeName ];
|
self.linkAttributeNames = DefaultLinkAttributeNames;
|
||||||
|
|
||||||
// Accessibility
|
// Accessibility
|
||||||
self.isAccessibilityElement = YES;
|
self.isAccessibilityElement = YES;
|
||||||
@@ -155,6 +166,8 @@ static NSString *ASTextNodeTruncationTokenAttributeName = @"ASTextNodeTruncation
|
|||||||
if (_shadowColor != NULL) {
|
if (_shadowColor != NULL) {
|
||||||
CGColorRelease(_shadowColor);
|
CGColorRelease(_shadowColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[self _invalidateRenderer];
|
||||||
|
|
||||||
if (_longPressGestureRecognizer) {
|
if (_longPressGestureRecognizer) {
|
||||||
_longPressGestureRecognizer.delegate = nil;
|
_longPressGestureRecognizer.delegate = nil;
|
||||||
@@ -187,6 +200,8 @@ static NSString *ASTextNodeTruncationTokenAttributeName = @"ASTextNodeTruncation
|
|||||||
return [[self _renderer] size];
|
return [[self _renderer] size];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: Re-evaluate if it is still the right decision to clear the renderer at this stage.
|
||||||
|
// This code was written before TextKit and when 512MB devices were still the overwhelming majority.
|
||||||
- (void)displayDidFinish
|
- (void)displayDidFinish
|
||||||
{
|
{
|
||||||
[super displayDidFinish];
|
[super displayDidFinish];
|
||||||
@@ -261,16 +276,17 @@ static NSString *ASTextNodeTruncationTokenAttributeName = @"ASTextNodeTruncation
|
|||||||
- (void)_invalidateRenderer
|
- (void)_invalidateRenderer
|
||||||
{
|
{
|
||||||
ASDN::MutexLocker l(_rendererLock);
|
ASDN::MutexLocker l(_rendererLock);
|
||||||
|
|
||||||
if (_renderer) {
|
if (_renderer) {
|
||||||
// Destruction of the layout managers/containers/text storage is quite
|
// Destruction of the layout managers/containers/text storage is quite
|
||||||
// expensive, and can take some time, so we dispatch onto a bg queue to
|
// expensive, and can take some time, so we dispatch onto a bg queue to
|
||||||
// actually dealloc.
|
// actually dealloc.
|
||||||
__block ASTextKitRenderer *renderer = _renderer;
|
__block ASTextKitRenderer *renderer = _renderer;
|
||||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
ASPerformBlockOnBackgroundThread(^{
|
||||||
renderer = nil;
|
renderer = nil;
|
||||||
});
|
});
|
||||||
|
_renderer = nil;
|
||||||
}
|
}
|
||||||
_renderer = nil;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_invalidateRendererIfNeeded
|
- (void)_invalidateRendererIfNeeded
|
||||||
@@ -318,7 +334,8 @@ static NSString *ASTextNodeTruncationTokenAttributeName = @"ASTextNodeTruncation
|
|||||||
|
|
||||||
#pragma mark - Modifying User Text
|
#pragma mark - Modifying User Text
|
||||||
|
|
||||||
- (void)setAttributedString:(NSAttributedString *)attributedString {
|
- (void)setAttributedString:(NSAttributedString *)attributedString
|
||||||
|
{
|
||||||
if (ASObjectIsEqual(attributedString, _attributedString)) {
|
if (ASObjectIsEqual(attributedString, _attributedString)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,14 +13,23 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
|
|
||||||
@interface ASViewController : UIViewController
|
@interface ASViewController : UIViewController
|
||||||
|
|
||||||
|
- (instancetype)initWithNode:(ASDisplayNode *)node NS_DESIGNATED_INITIALIZER;
|
||||||
|
|
||||||
@property (nonatomic, strong, readonly) ASDisplayNode *node;
|
@property (nonatomic, strong, readonly) ASDisplayNode *node;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @abstract Passthrough property to the the .interfaceState of the node.
|
||||||
|
* @return The current ASInterfaceState of the node, indicating whether it is visible and other situational properties.
|
||||||
|
* @see ASInterfaceState
|
||||||
|
*/
|
||||||
|
@property (nonatomic, readonly) ASInterfaceState interfaceState;
|
||||||
|
|
||||||
|
|
||||||
// AsyncDisplayKit 2.0 BETA: This property is still being tested, but it allows
|
// AsyncDisplayKit 2.0 BETA: This property is still being tested, but it allows
|
||||||
// blocking as a view controller becomes visible to ensure no placeholders flash onscreen.
|
// blocking as a view controller becomes visible to ensure no placeholders flash onscreen.
|
||||||
// Refer to examples/SynchronousConcurrency, AsyncViewController.m
|
// Refer to examples/SynchronousConcurrency, AsyncViewController.m
|
||||||
@property (nonatomic, assign) BOOL neverShowPlaceholders;
|
@property (nonatomic, assign) BOOL neverShowPlaceholders;
|
||||||
|
|
||||||
- (instancetype)initWithNode:(ASDisplayNode *)node;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The constrained size used to measure the backing node.
|
* The constrained size used to measure the backing node.
|
||||||
|
|||||||
@@ -16,6 +16,16 @@
|
|||||||
BOOL _ensureDisplayed;
|
BOOL _ensureDisplayed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
|
||||||
|
{
|
||||||
|
return [self initWithNode:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)initWithCoder:(NSCoder *)aDecoder
|
||||||
|
{
|
||||||
|
return [self initWithNode:nil];
|
||||||
|
}
|
||||||
|
|
||||||
- (instancetype)initWithNode:(ASDisplayNode *)node
|
- (instancetype)initWithNode:(ASDisplayNode *)node
|
||||||
{
|
{
|
||||||
if (!(self = [super initWithNibName:nil bundle:nil])) {
|
if (!(self = [super initWithNibName:nil bundle:nil])) {
|
||||||
@@ -65,4 +75,9 @@
|
|||||||
return ASSizeRangeMake(viewSize, viewSize);
|
return ASSizeRangeMake(viewSize, viewSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (ASInterfaceState)interfaceState
|
||||||
|
{
|
||||||
|
return _node.interfaceState;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
#import <AsyncDisplayKit/ASDimension.h>
|
#import <AsyncDisplayKit/ASDimension.h>
|
||||||
|
|
||||||
@class ASCollectionView;
|
@class ASCollectionView;
|
||||||
@protocol ASCollectionViewDelegate;
|
@protocol ASCollectionDelegate;
|
||||||
|
|
||||||
@protocol ASCollectionViewLayoutInspecting <NSObject>
|
@protocol ASCollectionViewLayoutInspecting <NSObject>
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@
|
|||||||
*
|
*
|
||||||
* @discussion A great time to update perform selector caches!
|
* @discussion A great time to update perform selector caches!
|
||||||
*/
|
*/
|
||||||
- (void)didChangeCollectionViewDelegate:(id<ASCollectionViewDelegate>)delegate;
|
- (void)didChangeCollectionViewDelegate:(id<ASCollectionDelegate>)delegate;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)didChangeCollectionViewDelegate:(id<ASCollectionViewDelegate>)delegate;
|
- (void)didChangeCollectionViewDelegate:(id<ASCollectionDelegate>)delegate;
|
||||||
{
|
{
|
||||||
if (delegate == nil) {
|
if (delegate == nil) {
|
||||||
_delegateImplementsReferenceSizeForHeader = NO;
|
_delegateImplementsReferenceSizeForHeader = NO;
|
||||||
|
|||||||
55
AsyncDisplayKit/Details/ASDelegateProxy.h
Normal file
55
AsyncDisplayKit/Details/ASDelegateProxy.h
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
/* Copyright (c) 2015-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>
|
||||||
|
|
||||||
|
@class ASDelegateProxy;
|
||||||
|
@protocol ASDelegateProxyInterceptor
|
||||||
|
@required
|
||||||
|
// Called if the target object is discovered to be nil if it had been non-nil at init time.
|
||||||
|
// This happens if the object is deallocated, because the proxy must maintain a weak reference to avoid cycles.
|
||||||
|
// Though the target object may become nil, the interceptor must not; it is assumed the interceptor owns the proxy.
|
||||||
|
- (void)proxyTargetHasDeallocated:(ASDelegateProxy *)proxy;
|
||||||
|
@end
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stand-in for delegates like UITableView or UICollectionView's delegate / dataSource.
|
||||||
|
* Any selectors flagged by "interceptsSelector" are routed to the interceptor object and are not delivered to the target.
|
||||||
|
* Everything else leaves AsyncDisplayKit safely and arrives at the original target object.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@interface ASDelegateProxy : NSProxy
|
||||||
|
|
||||||
|
- (instancetype)initWithTarget:(id<NSObject>)target interceptor:(id <ASDelegateProxyInterceptor>)interceptor;
|
||||||
|
|
||||||
|
// This method must be overridden by a subclass.
|
||||||
|
- (BOOL)interceptsSelector:(SEL)selector;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ASTableView intercepts and/or overrides a few of UITableView's critical data source and delegate methods.
|
||||||
|
*
|
||||||
|
* Any selector included in this function *MUST* be implemented by ASTableView.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@interface ASTableViewProxy : ASDelegateProxy
|
||||||
|
@end
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ASCollectionView intercepts and/or overrides a few of UICollectionView's critical data source and delegate methods.
|
||||||
|
*
|
||||||
|
* Any selector included in this function *MUST* be implemented by ASCollectionView.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@interface ASCollectionViewProxy : ASDelegateProxy
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface ASPagerNodeProxy : ASDelegateProxy
|
||||||
|
@end
|
||||||
|
|
||||||
127
AsyncDisplayKit/Details/ASDelegateProxy.m
Normal file
127
AsyncDisplayKit/Details/ASDelegateProxy.m
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
/* Copyright (c) 2015-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 "ASDelegateProxy.h"
|
||||||
|
#import "ASTableView.h"
|
||||||
|
#import "ASCollectionView.h"
|
||||||
|
#import "ASAssert.h"
|
||||||
|
|
||||||
|
@implementation ASTableViewProxy
|
||||||
|
|
||||||
|
- (BOOL)interceptsSelector:(SEL)selector
|
||||||
|
{
|
||||||
|
return (
|
||||||
|
// handled by ASTableView node<->cell machinery
|
||||||
|
selector == @selector(tableView:cellForRowAtIndexPath:) ||
|
||||||
|
selector == @selector(tableView:heightForRowAtIndexPath:) ||
|
||||||
|
|
||||||
|
// handled by ASRangeController
|
||||||
|
selector == @selector(numberOfSectionsInTableView:) ||
|
||||||
|
selector == @selector(tableView:numberOfRowsInSection:) ||
|
||||||
|
|
||||||
|
// used for ASRangeController visibility updates
|
||||||
|
selector == @selector(tableView:willDisplayCell:forRowAtIndexPath:) ||
|
||||||
|
selector == @selector(tableView:didEndDisplayingCell:forRowAtIndexPath:) ||
|
||||||
|
|
||||||
|
// used for batch fetching API
|
||||||
|
selector == @selector(scrollViewWillEndDragging:withVelocity:targetContentOffset:)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation ASCollectionViewProxy
|
||||||
|
|
||||||
|
- (BOOL)interceptsSelector:(SEL)selector
|
||||||
|
{
|
||||||
|
return (
|
||||||
|
// handled by ASCollectionView node<->cell machinery
|
||||||
|
selector == @selector(collectionView:cellForItemAtIndexPath:) ||
|
||||||
|
selector == @selector(collectionView:layout:sizeForItemAtIndexPath:) ||
|
||||||
|
selector == @selector(collectionView:viewForSupplementaryElementOfKind:atIndexPath:) ||
|
||||||
|
|
||||||
|
// handled by ASRangeController
|
||||||
|
selector == @selector(numberOfSectionsInCollectionView:) ||
|
||||||
|
selector == @selector(collectionView:numberOfItemsInSection:) ||
|
||||||
|
|
||||||
|
// used for ASRangeController visibility updates
|
||||||
|
selector == @selector(collectionView:willDisplayCell:forItemAtIndexPath:) ||
|
||||||
|
selector == @selector(collectionView:didEndDisplayingCell:forItemAtIndexPath:) ||
|
||||||
|
|
||||||
|
// used for batch fetching API
|
||||||
|
selector == @selector(scrollViewWillEndDragging:withVelocity:targetContentOffset:)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation ASPagerNodeProxy
|
||||||
|
|
||||||
|
- (BOOL)interceptsSelector:(SEL)selector
|
||||||
|
{
|
||||||
|
return (
|
||||||
|
// handled by ASPagerNodeDataSource node<->cell machinery
|
||||||
|
selector == @selector(collectionView:nodeForItemAtIndexPath:) ||
|
||||||
|
selector == @selector(collectionView:numberOfItemsInSection:) ||
|
||||||
|
selector == @selector(collectionView:constrainedSizeForNodeAtIndexPath:)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation ASDelegateProxy {
|
||||||
|
id <NSObject> __weak _target;
|
||||||
|
id <ASDelegateProxyInterceptor> __weak _interceptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)initWithTarget:(id <NSObject>)target interceptor:(id <ASDelegateProxyInterceptor>)interceptor
|
||||||
|
{
|
||||||
|
// -[NSProxy init] is undefined
|
||||||
|
if (!self) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASDisplayNodeAssert(interceptor, @"interceptor must not be nil");
|
||||||
|
|
||||||
|
_target = target ? : [NSNull null];
|
||||||
|
_interceptor = interceptor;
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)respondsToSelector:(SEL)aSelector
|
||||||
|
{
|
||||||
|
if ([self interceptsSelector:aSelector]) {
|
||||||
|
return (_interceptor != nil);
|
||||||
|
} else {
|
||||||
|
// Also return NO if _target has become nil due to zeroing weak reference (or placeholder initialization).
|
||||||
|
return [_target respondsToSelector:aSelector];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)forwardingTargetForSelector:(SEL)aSelector
|
||||||
|
{
|
||||||
|
if ([self interceptsSelector:aSelector]) {
|
||||||
|
return _interceptor;
|
||||||
|
} else {
|
||||||
|
if (_target) {
|
||||||
|
return [_target respondsToSelector:aSelector] ? _target : nil;
|
||||||
|
} else {
|
||||||
|
[_interceptor proxyTargetHasDeallocated:self];
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)interceptsSelector:(SEL)selector
|
||||||
|
{
|
||||||
|
ASDisplayNodeAssert(NO, @"This method must be overridden by subclasses.");
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -10,19 +10,53 @@
|
|||||||
|
|
||||||
#import "_ASAsyncTransaction.h"
|
#import "_ASAsyncTransaction.h"
|
||||||
#import "_ASAsyncTransactionGroup.h"
|
#import "_ASAsyncTransactionGroup.h"
|
||||||
|
#import <objc/runtime.h>
|
||||||
|
|
||||||
|
static const char *ASDisplayNodeAssociatedTransactionsKey = "ASAssociatedTransactions";
|
||||||
|
static const char *ASDisplayNodeAssociatedCurrentTransactionKey = "ASAssociatedCurrentTransaction";
|
||||||
|
|
||||||
@implementation CALayer (ASAsyncTransactionContainerTransactions)
|
@implementation CALayer (ASAsyncTransactionContainerTransactions)
|
||||||
@dynamic asyncdisplaykit_asyncLayerTransactions;
|
|
||||||
@dynamic asyncdisplaykit_currentAsyncLayerTransaction;
|
- (_ASAsyncTransaction *)asyncdisplaykit_currentAsyncLayerTransaction
|
||||||
|
{
|
||||||
|
return objc_getAssociatedObject(self, ASDisplayNodeAssociatedCurrentTransactionKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)asyncdisplaykit_setCurrentAsyncLayerTransaction:(_ASAsyncTransaction *)transaction
|
||||||
|
{
|
||||||
|
objc_setAssociatedObject(self, ASDisplayNodeAssociatedCurrentTransactionKey, transaction, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSHashTable *)asyncdisplaykit_asyncLayerTransactions
|
||||||
|
{
|
||||||
|
return objc_getAssociatedObject(self, ASDisplayNodeAssociatedTransactionsKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)asyncdisplaykit_setAsyncLayerTransactions:(NSHashTable *)transactions
|
||||||
|
{
|
||||||
|
objc_setAssociatedObject(self, ASDisplayNodeAssociatedTransactionsKey, transactions, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||||
|
}
|
||||||
|
|
||||||
// No-ops in the base class. Mostly exposed for testing.
|
// No-ops in the base class. Mostly exposed for testing.
|
||||||
- (void)asyncdisplaykit_asyncTransactionContainerWillBeginTransaction:(_ASAsyncTransaction *)transaction {}
|
- (void)asyncdisplaykit_asyncTransactionContainerWillBeginTransaction:(_ASAsyncTransaction *)transaction {}
|
||||||
- (void)asyncdisplaykit_asyncTransactionContainerDidCompleteTransaction:(_ASAsyncTransaction *)transaction {}
|
- (void)asyncdisplaykit_asyncTransactionContainerDidCompleteTransaction:(_ASAsyncTransaction *)transaction {}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
static const char *ASAsyncTransactionIsContainerKey = "ASTransactionIsContainer";
|
||||||
|
|
||||||
@implementation CALayer (ASDisplayNodeAsyncTransactionContainer)
|
@implementation CALayer (ASDisplayNodeAsyncTransactionContainer)
|
||||||
|
|
||||||
@dynamic asyncdisplaykit_asyncTransactionContainer;
|
- (BOOL)asyncdisplaykit_isAsyncTransactionContainer
|
||||||
|
{
|
||||||
|
CFBooleanRef isContainerBool = (__bridge CFBooleanRef)objc_getAssociatedObject(self, ASAsyncTransactionIsContainerKey);
|
||||||
|
BOOL isContainer = (isContainerBool == kCFBooleanTrue);
|
||||||
|
return isContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)asyncdisplaykit_setAsyncTransactionContainer:(BOOL)isContainer
|
||||||
|
{
|
||||||
|
objc_setAssociatedObject(self, ASAsyncTransactionIsContainerKey, (id)(isContainer ? kCFBooleanTrue : kCFBooleanFalse), OBJC_ASSOCIATION_ASSIGN);
|
||||||
|
}
|
||||||
|
|
||||||
- (ASAsyncTransactionContainerState)asyncdisplaykit_asyncTransactionContainerState
|
- (ASAsyncTransactionContainerState)asyncdisplaykit_asyncTransactionContainerState
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -39,33 +39,34 @@
|
|||||||
|
|
||||||
- (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize
|
- (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize
|
||||||
{
|
{
|
||||||
CGSize size = {
|
CGSize maxConstrainedSize = CGSizeMake(constrainedSize.max.width, constrainedSize.max.height);
|
||||||
constrainedSize.max.width,
|
|
||||||
constrainedSize.max.height
|
NSArray *children = self.children;
|
||||||
};
|
NSMutableArray *sublayouts = [NSMutableArray arrayWithCapacity:children.count];
|
||||||
|
|
||||||
NSMutableArray *sublayouts = [NSMutableArray arrayWithCapacity:self.children.count];
|
for (id<ASLayoutable> child in children) {
|
||||||
for (id<ASLayoutable> child in self.children) {
|
CGPoint layoutPosition = child.layoutPosition;
|
||||||
CGSize autoMaxSize = {
|
CGSize autoMaxSize = CGSizeMake(maxConstrainedSize.width - layoutPosition.x,
|
||||||
constrainedSize.max.width - child.layoutPosition.x,
|
maxConstrainedSize.height - layoutPosition.y);
|
||||||
constrainedSize.max.height - child.layoutPosition.y
|
|
||||||
};
|
ASRelativeSizeRange childSizeRange = child.sizeRange;
|
||||||
ASSizeRange childConstraint = ASRelativeSizeRangeEqualToRelativeSizeRange(ASRelativeSizeRangeUnconstrained, child.sizeRange)
|
BOOL childIsUnconstrained = ASRelativeSizeRangeEqualToRelativeSizeRange(ASRelativeSizeRangeUnconstrained, childSizeRange);
|
||||||
? ASSizeRangeMake({0, 0}, autoMaxSize)
|
ASSizeRange childConstraint = childIsUnconstrained ? ASSizeRangeMake({0, 0}, autoMaxSize)
|
||||||
: ASRelativeSizeRangeResolve(child.sizeRange, size);
|
: ASRelativeSizeRangeResolve(childSizeRange, maxConstrainedSize);
|
||||||
|
|
||||||
ASLayout *sublayout = [child measureWithSizeRange:childConstraint];
|
ASLayout *sublayout = [child measureWithSizeRange:childConstraint];
|
||||||
sublayout.position = child.layoutPosition;
|
sublayout.position = layoutPosition;
|
||||||
[sublayouts addObject:sublayout];
|
[sublayouts addObject:sublayout];
|
||||||
}
|
}
|
||||||
|
|
||||||
size.width = constrainedSize.min.width;
|
CGSize size = CGSizeMake(constrainedSize.min.width, constrainedSize.min.height);
|
||||||
for (ASLayout *sublayout in sublayouts) {
|
|
||||||
size.width = MAX(size.width, sublayout.position.x + sublayout.size.width);
|
|
||||||
}
|
|
||||||
|
|
||||||
size.height = constrainedSize.min.height;
|
|
||||||
for (ASLayout *sublayout in sublayouts) {
|
for (ASLayout *sublayout in sublayouts) {
|
||||||
size.height = MAX(size.height, sublayout.position.y + sublayout.size.height);
|
CGPoint sublayoutPosition = sublayout.position;
|
||||||
|
CGSize sublayoutSize = sublayout.size;
|
||||||
|
|
||||||
|
size.width = MAX(size.width, sublayoutPosition.x + sublayoutSize.width);
|
||||||
|
size.height = MAX(size.height, sublayoutPosition.y + sublayoutSize.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
return [ASLayout layoutWithLayoutableObject:self
|
return [ASLayout layoutWithLayoutableObject:self
|
||||||
@@ -75,12 +76,12 @@
|
|||||||
|
|
||||||
- (void)setChild:(id<ASLayoutable>)child forIdentifier:(NSString *)identifier
|
- (void)setChild:(id<ASLayoutable>)child forIdentifier:(NSString *)identifier
|
||||||
{
|
{
|
||||||
ASDisplayNodeAssert(NO, @"ASStackLayoutSpec only supports setChildren");
|
ASDisplayNodeAssert(NO, @"ASStaticLayoutSpec only supports setChildren");
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id<ASLayoutable>)childForIdentifier:(NSString *)identifier
|
- (id<ASLayoutable>)childForIdentifier:(NSString *)identifier
|
||||||
{
|
{
|
||||||
ASDisplayNodeAssert(NO, @"ASStackLayoutSpec only supports children");
|
ASDisplayNodeAssert(NO, @"ASStaticLayoutSpec only supports children");
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -175,8 +175,6 @@ static void __ASDisplayLayerDecrementConcurrentDisplayCount(BOOL displayIsAsync,
|
|||||||
|
|
||||||
- (asyncdisplaykit_async_transaction_operation_block_t)_displayBlockWithAsynchronous:(BOOL)asynchronous isCancelledBlock:(asdisplaynode_iscancelled_block_t)isCancelledBlock rasterizing:(BOOL)rasterizing
|
- (asyncdisplaykit_async_transaction_operation_block_t)_displayBlockWithAsynchronous:(BOOL)asynchronous isCancelledBlock:(asdisplaynode_iscancelled_block_t)isCancelledBlock rasterizing:(BOOL)rasterizing
|
||||||
{
|
{
|
||||||
id nodeClass = [self class];
|
|
||||||
|
|
||||||
asyncdisplaykit_async_transaction_operation_block_t displayBlock = nil;
|
asyncdisplaykit_async_transaction_operation_block_t displayBlock = nil;
|
||||||
|
|
||||||
ASDisplayNodeAssert(rasterizing || !(_hierarchyState & ASHierarchyStateRasterized), @"Rasterized descendants should never display unless being drawn into the rasterized container.");
|
ASDisplayNodeAssert(rasterizing || !(_hierarchyState & ASHierarchyStateRasterized), @"Rasterized descendants should never display unless being drawn into the rasterized container.");
|
||||||
@@ -235,7 +233,7 @@ static void __ASDisplayLayerDecrementConcurrentDisplayCount(BOOL displayIsAsync,
|
|||||||
|
|
||||||
ASDN_DELAY_FOR_DISPLAY();
|
ASDN_DELAY_FOR_DISPLAY();
|
||||||
|
|
||||||
UIImage *result = [nodeClass displayWithParameters:drawParameters isCancelled:isCancelledBlock];
|
UIImage *result = [[self class] displayWithParameters:drawParameters isCancelled:isCancelledBlock];
|
||||||
__ASDisplayLayerDecrementConcurrentDisplayCount(asynchronous, rasterizing);
|
__ASDisplayLayerDecrementConcurrentDisplayCount(asynchronous, rasterizing);
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
@@ -265,7 +263,7 @@ static void __ASDisplayLayerDecrementConcurrentDisplayCount(BOOL displayIsAsync,
|
|||||||
UIGraphicsBeginImageContextWithOptions(bounds.size, opaque, contentsScaleForDisplay);
|
UIGraphicsBeginImageContextWithOptions(bounds.size, opaque, contentsScaleForDisplay);
|
||||||
}
|
}
|
||||||
|
|
||||||
[nodeClass drawRect:bounds withParameters:drawParameters isCancelled:isCancelledBlock isRasterizing:rasterizing];
|
[[self class] drawRect:bounds withParameters:drawParameters isCancelled:isCancelledBlock isRasterizing:rasterizing];
|
||||||
|
|
||||||
if (isCancelledBlock()) {
|
if (isCancelledBlock()) {
|
||||||
if (!rasterizing) {
|
if (!rasterizing) {
|
||||||
|
|||||||
@@ -59,6 +59,9 @@ typedef NS_OPTIONS(NSUInteger, ASHierarchyState)
|
|||||||
ASHierarchyState _hierarchyState;
|
ASHierarchyState _hierarchyState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The view class to use when creating a new display node instance. Defaults to _ASDisplayView.
|
||||||
|
+ (Class)viewClass;
|
||||||
|
|
||||||
// These methods are recursive, and either union or remove the provided interfaceState to all sub-elements.
|
// These methods are recursive, and either union or remove the provided interfaceState to all sub-elements.
|
||||||
- (void)enterInterfaceState:(ASInterfaceState)interfaceState;
|
- (void)enterInterfaceState:(ASInterfaceState)interfaceState;
|
||||||
- (void)exitInterfaceState:(ASInterfaceState)interfaceState;
|
- (void)exitInterfaceState:(ASInterfaceState)interfaceState;
|
||||||
|
|||||||
@@ -446,19 +446,27 @@
|
|||||||
{
|
{
|
||||||
_bridge_prologue;
|
_bridge_prologue;
|
||||||
if (__loaded) {
|
if (__loaded) {
|
||||||
return ASDisplayNodeUIContentModeFromCAContentsGravity(_layer.contentsGravity);
|
if (_flags.layerBacked) {
|
||||||
|
return ASDisplayNodeUIContentModeFromCAContentsGravity(_layer.contentsGravity);
|
||||||
|
} else {
|
||||||
|
return _view.contentMode;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return self.pendingViewState.contentMode;
|
return self.pendingViewState.contentMode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setContentMode:(UIViewContentMode)mode
|
- (void)setContentMode:(UIViewContentMode)contentMode
|
||||||
{
|
{
|
||||||
_bridge_prologue;
|
_bridge_prologue;
|
||||||
if (__loaded) {
|
if (__loaded) {
|
||||||
_layer.contentsGravity = ASDisplayNodeCAContentsGravityFromUIContentMode(mode);
|
if (_flags.layerBacked) {
|
||||||
|
_layer.contentsGravity = ASDisplayNodeCAContentsGravityFromUIContentMode(contentMode);
|
||||||
|
} else {
|
||||||
|
_view.contentMode = contentMode;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
self.pendingViewState.contentMode = mode;
|
self.pendingViewState.contentMode = contentMode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -144,6 +144,9 @@ typedef NS_OPTIONS(NSUInteger, ASDisplayNodeMethodOverrides)
|
|||||||
// Call didExitHierarchy if necessary and set inHierarchy = NO if visibility notifications are enabled on all of its parents
|
// Call didExitHierarchy if necessary and set inHierarchy = NO if visibility notifications are enabled on all of its parents
|
||||||
- (void)__exitHierarchy;
|
- (void)__exitHierarchy;
|
||||||
|
|
||||||
|
// Helper method to summarize whether or not the node run through the display process
|
||||||
|
- (BOOL)__implementsDisplay;
|
||||||
|
|
||||||
// Display the node's view/layer immediately on the current thread, bypassing the background thread rendering. Will be deprecated.
|
// Display the node's view/layer immediately on the current thread, bypassing the background thread rendering. Will be deprecated.
|
||||||
- (void)displayImmediately;
|
- (void)displayImmediately;
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ ASDISPLAYNODE_EXTERN_C_BEGIN
|
|||||||
BOOL ASSubclassOverridesSelector(Class superclass, Class subclass, SEL selector);
|
BOOL ASSubclassOverridesSelector(Class superclass, Class subclass, SEL selector);
|
||||||
BOOL ASSubclassOverridesClassSelector(Class superclass, Class subclass, SEL selector);
|
BOOL ASSubclassOverridesClassSelector(Class superclass, Class subclass, SEL selector);
|
||||||
void ASPerformBlockOnMainThread(void (^block)());
|
void ASPerformBlockOnMainThread(void (^block)());
|
||||||
|
void ASPerformBlockOnBackgroundThread(void (^block)()); // DISPATCH_QUEUE_PRIORITY_DEFAULT
|
||||||
|
|
||||||
CGFloat ASScreenScale();
|
CGFloat ASScreenScale();
|
||||||
|
|
||||||
|
|||||||
@@ -57,6 +57,18 @@ void ASPerformBlockOnMainThread(void (^block)())
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ASPerformBlockOnBackgroundThread(void (^block)())
|
||||||
|
{
|
||||||
|
if ([NSThread isMainThread]) {
|
||||||
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||||
|
block();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
block();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
CGFloat ASScreenScale()
|
CGFloat ASScreenScale()
|
||||||
{
|
{
|
||||||
static CGFloat _scale;
|
static CGFloat _scale;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#import "_ASCoreAnimationExtras.h"
|
#import "_ASCoreAnimationExtras.h"
|
||||||
|
#import "ASEqualityHelpers.h"
|
||||||
#import "ASAssert.h"
|
#import "ASAssert.h"
|
||||||
|
|
||||||
extern void ASDisplayNodeSetupLayerContentsWithResizableImage(CALayer *layer, UIImage *image)
|
extern void ASDisplayNodeSetupLayerContentsWithResizableImage(CALayer *layer, UIImage *image)
|
||||||
@@ -87,7 +87,8 @@ static const struct _UIContentModeStringLUTEntry UIContentModeDescriptionLUT[] =
|
|||||||
{UIViewContentModeBottomRight, @"bottomRight"},
|
{UIViewContentModeBottomRight, @"bottomRight"},
|
||||||
};
|
};
|
||||||
|
|
||||||
NSString *ASDisplayNodeNSStringFromUIContentMode(UIViewContentMode contentMode) {
|
NSString *ASDisplayNodeNSStringFromUIContentMode(UIViewContentMode contentMode)
|
||||||
|
{
|
||||||
for (int i=0; i< ARRAY_COUNT(UIContentModeDescriptionLUT); i++) {
|
for (int i=0; i< ARRAY_COUNT(UIContentModeDescriptionLUT); i++) {
|
||||||
if (UIContentModeDescriptionLUT[i].contentMode == contentMode) {
|
if (UIContentModeDescriptionLUT[i].contentMode == contentMode) {
|
||||||
return UIContentModeDescriptionLUT[i].string;
|
return UIContentModeDescriptionLUT[i].string;
|
||||||
@@ -96,16 +97,10 @@ NSString *ASDisplayNodeNSStringFromUIContentMode(UIViewContentMode contentMode)
|
|||||||
return [NSString stringWithFormat:@"%d", (int)contentMode];
|
return [NSString stringWithFormat:@"%d", (int)contentMode];
|
||||||
}
|
}
|
||||||
|
|
||||||
UIViewContentMode ASDisplayNodeUIContentModeFromNSString(NSString *string) {
|
UIViewContentMode ASDisplayNodeUIContentModeFromNSString(NSString *string)
|
||||||
// If you passed one of the constants (this is just an optimization to avoid string comparison)
|
{
|
||||||
for (int i=0; i < ARRAY_COUNT(UIContentModeDescriptionLUT); i++) {
|
for (int i=0; i < ARRAY_COUNT(UIContentModeDescriptionLUT); i++) {
|
||||||
if (UIContentModeDescriptionLUT[i].string == string) {
|
if (ASObjectIsEqual(UIContentModeDescriptionLUT[i].string, string)) {
|
||||||
return UIContentModeDescriptionLUT[i].contentMode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If you passed something isEqualToString: to one of the constants
|
|
||||||
for (int i=0; i < ARRAY_COUNT(UIContentModeDescriptionLUT); i++) {
|
|
||||||
if ([UIContentModeDescriptionLUT[i].string isEqualToString:string]) {
|
|
||||||
return UIContentModeDescriptionLUT[i].contentMode;
|
return UIContentModeDescriptionLUT[i].contentMode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -124,20 +119,34 @@ NSString *const ASDisplayNodeCAContentsGravityFromUIContentMode(UIViewContentMod
|
|||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define ContentModeCacheSize 10
|
||||||
UIViewContentMode ASDisplayNodeUIContentModeFromCAContentsGravity(NSString *const contentsGravity)
|
UIViewContentMode ASDisplayNodeUIContentModeFromCAContentsGravity(NSString *const contentsGravity)
|
||||||
{
|
{
|
||||||
// If you passed one of the constants (this is just an optimization to avoid string comparison)
|
static int currentCacheIndex = 0;
|
||||||
for (int i=0; i < ARRAY_COUNT(UIContentModeCAGravityLUT); i++) {
|
static NSMutableArray *cachedStrings = [NSMutableArray arrayWithCapacity:ContentModeCacheSize];
|
||||||
if (UIContentModeCAGravityLUT[i].string == contentsGravity) {
|
static UIViewContentMode cachedModes[ContentModeCacheSize] = {};
|
||||||
return UIContentModeCAGravityLUT[i].contentMode;
|
|
||||||
}
|
NSInteger foundCacheIndex = [cachedStrings indexOfObjectIdenticalTo:contentsGravity];
|
||||||
}
|
if (foundCacheIndex != NSNotFound && foundCacheIndex < ContentModeCacheSize) {
|
||||||
// If you passed something isEqualToString: to one of the constants
|
return cachedModes[foundCacheIndex];
|
||||||
for (int i=0; i < ARRAY_COUNT(UIContentModeCAGravityLUT); i++) {
|
}
|
||||||
if ([UIContentModeCAGravityLUT[i].string isEqualToString:contentsGravity]) {
|
|
||||||
return UIContentModeCAGravityLUT[i].contentMode;
|
for (int i = 0; i < ARRAY_COUNT(UIContentModeCAGravityLUT); i++) {
|
||||||
|
if (ASObjectIsEqual(UIContentModeCAGravityLUT[i].string, contentsGravity)) {
|
||||||
|
UIViewContentMode foundContentMode = UIContentModeCAGravityLUT[i].contentMode;
|
||||||
|
|
||||||
|
if (currentCacheIndex < ContentModeCacheSize) {
|
||||||
|
// Cache the input value. This is almost always a different pointer than in our LUT and will frequently
|
||||||
|
// be the same value for an overwhelming majority of inputs.
|
||||||
|
[cachedStrings addObject:contentsGravity];
|
||||||
|
cachedModes[currentCacheIndex] = foundContentMode;
|
||||||
|
currentCacheIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return foundContentMode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ASDisplayNodeCAssert(contentsGravity, @"Encountered an unknown contentsGravity \"%@\". Is this a new version of iOS?", contentsGravity);
|
ASDisplayNodeCAssert(contentsGravity, @"Encountered an unknown contentsGravity \"%@\". Is this a new version of iOS?", contentsGravity);
|
||||||
ASDisplayNodeCAssert(!contentsGravity, @"You passed nil to ASDisplayNodeUIContentModeFromCAContentsGravity. We're falling back to resize, but this is probably a bug.");
|
ASDisplayNodeCAssert(!contentsGravity, @"You passed nil to ASDisplayNodeUIContentModeFromCAContentsGravity. We're falling back to resize, but this is probably a bug.");
|
||||||
// If asserts disabled, fall back to this
|
// If asserts disabled, fall back to this
|
||||||
|
|||||||
@@ -135,19 +135,24 @@
|
|||||||
@synthesize borderColor=borderColor;
|
@synthesize borderColor=borderColor;
|
||||||
@synthesize asyncdisplaykit_asyncTransactionContainer=asyncTransactionContainer;
|
@synthesize asyncdisplaykit_asyncTransactionContainer=asyncTransactionContainer;
|
||||||
|
|
||||||
|
|
||||||
|
static CGColorRef blackColorRef = NULL;
|
||||||
|
static UIColor *defaultTintColor = nil;
|
||||||
|
|
||||||
- (id)init
|
- (id)init
|
||||||
{
|
{
|
||||||
if (!(self = [super init]))
|
if (!(self = [super init]))
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
// Default UIKit color is an RGB color
|
|
||||||
static CGColorRef black;
|
|
||||||
static dispatch_once_t onceToken;
|
static dispatch_once_t onceToken;
|
||||||
dispatch_once(&onceToken, ^{
|
dispatch_once(&onceToken, ^{
|
||||||
|
// Default UIKit color is an RGB color
|
||||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||||
black = CGColorCreate(colorSpace, (CGFloat[]){0,0,0,1} );
|
blackColorRef = CGColorCreate(colorSpace, (CGFloat[]){0,0,0,1} );
|
||||||
CFRetain(black);
|
CFRetain(blackColorRef);
|
||||||
CGColorSpaceRelease(colorSpace);
|
CGColorSpaceRelease(colorSpace);
|
||||||
|
defaultTintColor = [UIColor colorWithRed:0.0 green:0.478 blue:1.0 alpha:1.0];
|
||||||
});
|
});
|
||||||
|
|
||||||
// Set defaults, these come from the defaults specified in CALayer and UIView
|
// Set defaults, these come from the defaults specified in CALayer and UIView
|
||||||
@@ -156,7 +161,7 @@
|
|||||||
frame = CGRectZero;
|
frame = CGRectZero;
|
||||||
bounds = CGRectZero;
|
bounds = CGRectZero;
|
||||||
backgroundColor = nil;
|
backgroundColor = nil;
|
||||||
tintColor = [UIColor colorWithRed:0.0 green:0.478 blue:1.0 alpha:1.0];
|
tintColor = defaultTintColor;
|
||||||
contents = nil;
|
contents = nil;
|
||||||
isHidden = NO;
|
isHidden = NO;
|
||||||
needsDisplayOnBoundsChange = NO;
|
needsDisplayOnBoundsChange = NO;
|
||||||
@@ -172,14 +177,12 @@
|
|||||||
transform = CATransform3DIdentity;
|
transform = CATransform3DIdentity;
|
||||||
sublayerTransform = CATransform3DIdentity;
|
sublayerTransform = CATransform3DIdentity;
|
||||||
userInteractionEnabled = YES;
|
userInteractionEnabled = YES;
|
||||||
CFRetain(black);
|
shadowColor = blackColorRef;
|
||||||
shadowColor = black;
|
|
||||||
shadowOpacity = 0.0;
|
shadowOpacity = 0.0;
|
||||||
shadowOffset = CGSizeMake(0, -3);
|
shadowOffset = CGSizeMake(0, -3);
|
||||||
shadowRadius = 3;
|
shadowRadius = 3;
|
||||||
borderWidth = 0;
|
borderWidth = 0;
|
||||||
CFRetain(black);
|
borderColor = blackColorRef;
|
||||||
borderColor = black;
|
|
||||||
isAccessibilityElement = NO;
|
isAccessibilityElement = NO;
|
||||||
accessibilityLabel = nil;
|
accessibilityLabel = nil;
|
||||||
accessibilityHint = nil;
|
accessibilityHint = nil;
|
||||||
@@ -376,7 +379,9 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CGColorRelease(shadowColor);
|
if (shadowColor != blackColorRef) {
|
||||||
|
CGColorRelease(shadowColor);
|
||||||
|
}
|
||||||
shadowColor = color;
|
shadowColor = color;
|
||||||
CGColorRetain(shadowColor);
|
CGColorRetain(shadowColor);
|
||||||
|
|
||||||
@@ -413,7 +418,9 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CGColorRelease(borderColor);
|
if (borderColor != blackColorRef) {
|
||||||
|
CGColorRelease(borderColor);
|
||||||
|
}
|
||||||
borderColor = color;
|
borderColor = color;
|
||||||
CGColorRetain(borderColor);
|
CGColorRetain(borderColor);
|
||||||
|
|
||||||
@@ -1002,8 +1009,14 @@
|
|||||||
- (void)dealloc
|
- (void)dealloc
|
||||||
{
|
{
|
||||||
CGColorRelease(backgroundColor);
|
CGColorRelease(backgroundColor);
|
||||||
CGColorRelease(shadowColor);
|
|
||||||
CGColorRelease(borderColor);
|
if (shadowColor != blackColorRef) {
|
||||||
|
CGColorRelease(shadowColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (borderColor != blackColorRef) {
|
||||||
|
CGColorRelease(borderColor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -32,7 +32,9 @@ static NSCharacterSet *_defaultAvoidTruncationCharacterSet()
|
|||||||
|
|
||||||
@implementation ASTextKitRenderer {
|
@implementation ASTextKitRenderer {
|
||||||
CGSize _calculatedSize;
|
CGSize _calculatedSize;
|
||||||
|
BOOL _sizeIsCalculated;
|
||||||
}
|
}
|
||||||
|
@synthesize attributes = _attributes, context = _context, shadower = _shadower, truncater = _truncater;
|
||||||
|
|
||||||
#pragma mark - Initialization
|
#pragma mark - Initialization
|
||||||
|
|
||||||
@@ -42,30 +44,50 @@ static NSCharacterSet *_defaultAvoidTruncationCharacterSet()
|
|||||||
if (self = [super init]) {
|
if (self = [super init]) {
|
||||||
_constrainedSize = constrainedSize;
|
_constrainedSize = constrainedSize;
|
||||||
_attributes = attributes;
|
_attributes = attributes;
|
||||||
|
_sizeIsCalculated = NO;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (ASTextKitShadower *)shadower
|
||||||
|
{
|
||||||
|
if (!_shadower) {
|
||||||
|
ASTextKitAttributes attributes = _attributes;
|
||||||
_shadower = [[ASTextKitShadower alloc] initWithShadowOffset:attributes.shadowOffset
|
_shadower = [[ASTextKitShadower alloc] initWithShadowOffset:attributes.shadowOffset
|
||||||
shadowColor:attributes.shadowColor
|
shadowColor:attributes.shadowColor
|
||||||
shadowOpacity:attributes.shadowOpacity
|
shadowOpacity:attributes.shadowOpacity
|
||||||
shadowRadius:attributes.shadowRadius];
|
shadowRadius:attributes.shadowRadius];
|
||||||
|
}
|
||||||
|
return _shadower;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (ASTextKitTailTruncater *)truncater
|
||||||
|
{
|
||||||
|
if (!_truncater) {
|
||||||
|
ASTextKitAttributes attributes = _attributes;
|
||||||
// We must inset the constrained size by the size of the shadower.
|
// We must inset the constrained size by the size of the shadower.
|
||||||
CGSize shadowConstrainedSize = [_shadower insetSizeWithConstrainedSize:_constrainedSize];
|
CGSize shadowConstrainedSize = [[self shadower] insetSizeWithConstrainedSize:_constrainedSize];
|
||||||
|
_truncater = [[ASTextKitTailTruncater alloc] initWithContext:[self context]
|
||||||
|
truncationAttributedString:attributes.truncationAttributedString
|
||||||
|
avoidTailTruncationSet:attributes.avoidTailTruncationSet ?: _defaultAvoidTruncationCharacterSet()
|
||||||
|
constrainedSize:shadowConstrainedSize];
|
||||||
|
}
|
||||||
|
return _truncater;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (ASTextKitContext *)context
|
||||||
|
{
|
||||||
|
if (!_context) {
|
||||||
|
ASTextKitAttributes attributes = _attributes;
|
||||||
|
CGSize shadowConstrainedSize = [[self shadower] insetSizeWithConstrainedSize:_constrainedSize];
|
||||||
_context = [[ASTextKitContext alloc] initWithAttributedString:attributes.attributedString
|
_context = [[ASTextKitContext alloc] initWithAttributedString:attributes.attributedString
|
||||||
lineBreakMode:attributes.lineBreakMode
|
lineBreakMode:attributes.lineBreakMode
|
||||||
maximumNumberOfLines:attributes.maximumNumberOfLines
|
maximumNumberOfLines:attributes.maximumNumberOfLines
|
||||||
exclusionPaths:attributes.exclusionPaths
|
exclusionPaths:attributes.exclusionPaths
|
||||||
constrainedSize:shadowConstrainedSize
|
constrainedSize:shadowConstrainedSize
|
||||||
layoutManagerFactory:attributes.layoutManagerFactory];
|
layoutManagerFactory:attributes.layoutManagerFactory];
|
||||||
|
|
||||||
_truncater = [[ASTextKitTailTruncater alloc] initWithContext:_context
|
|
||||||
truncationAttributedString:attributes.truncationAttributedString
|
|
||||||
avoidTailTruncationSet:attributes.avoidTailTruncationSet ?: _defaultAvoidTruncationCharacterSet()
|
|
||||||
constrainedSize:shadowConstrainedSize];
|
|
||||||
|
|
||||||
[self _calculateSize];
|
|
||||||
}
|
}
|
||||||
return self;
|
return _context;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Sizing
|
#pragma mark - Sizing
|
||||||
@@ -74,14 +96,14 @@ static NSCharacterSet *_defaultAvoidTruncationCharacterSet()
|
|||||||
{
|
{
|
||||||
// Force glyph generation and layout, which may not have happened yet (and isn't triggered by
|
// Force glyph generation and layout, which may not have happened yet (and isn't triggered by
|
||||||
// -usedRectForTextContainer:).
|
// -usedRectForTextContainer:).
|
||||||
[_context performBlockWithLockedTextKitComponents:^(NSLayoutManager *layoutManager, NSTextStorage *textStorage, NSTextContainer *textContainer) {
|
[[self context] performBlockWithLockedTextKitComponents:^(NSLayoutManager *layoutManager, NSTextStorage *textStorage, NSTextContainer *textContainer) {
|
||||||
[layoutManager ensureLayoutForTextContainer:textContainer];
|
[layoutManager ensureLayoutForTextContainer:textContainer];
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
|
||||||
CGRect constrainedRect = {CGPointZero, _constrainedSize};
|
CGRect constrainedRect = {CGPointZero, _constrainedSize};
|
||||||
__block CGRect boundingRect;
|
__block CGRect boundingRect;
|
||||||
[_context performBlockWithLockedTextKitComponents:^(NSLayoutManager *layoutManager, NSTextStorage *textStorage, NSTextContainer *textContainer) {
|
[[self context] performBlockWithLockedTextKitComponents:^(NSLayoutManager *layoutManager, NSTextStorage *textStorage, NSTextContainer *textContainer) {
|
||||||
boundingRect = [layoutManager usedRectForTextContainer:textContainer];
|
boundingRect = [layoutManager usedRectForTextContainer:textContainer];
|
||||||
}];
|
}];
|
||||||
|
|
||||||
@@ -94,6 +116,10 @@ static NSCharacterSet *_defaultAvoidTruncationCharacterSet()
|
|||||||
|
|
||||||
- (CGSize)size
|
- (CGSize)size
|
||||||
{
|
{
|
||||||
|
if (!_sizeIsCalculated) {
|
||||||
|
[self _calculateSize];
|
||||||
|
_sizeIsCalculated = YES;
|
||||||
|
}
|
||||||
return _calculatedSize;
|
return _calculatedSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,13 +130,13 @@ static NSCharacterSet *_defaultAvoidTruncationCharacterSet()
|
|||||||
// We add an assertion so we can track the rare conditions where a graphics context is not present
|
// We add an assertion so we can track the rare conditions where a graphics context is not present
|
||||||
ASDisplayNodeAssertNotNil(context, @"This is no good without a context.");
|
ASDisplayNodeAssertNotNil(context, @"This is no good without a context.");
|
||||||
|
|
||||||
CGRect shadowInsetBounds = [_shadower insetRectWithConstrainedRect:bounds];
|
CGRect shadowInsetBounds = [[self shadower] insetRectWithConstrainedRect:bounds];
|
||||||
|
|
||||||
CGContextSaveGState(context);
|
CGContextSaveGState(context);
|
||||||
[_shadower setShadowInContext:context];
|
[[self shadower] setShadowInContext:context];
|
||||||
UIGraphicsPushContext(context);
|
UIGraphicsPushContext(context);
|
||||||
|
|
||||||
[_context performBlockWithLockedTextKitComponents:^(NSLayoutManager *layoutManager, NSTextStorage *textStorage, NSTextContainer *textContainer) {
|
[[self context] performBlockWithLockedTextKitComponents:^(NSLayoutManager *layoutManager, NSTextStorage *textStorage, NSTextContainer *textContainer) {
|
||||||
NSRange glyphRange = [layoutManager glyphRangeForTextContainer:textContainer];
|
NSRange glyphRange = [layoutManager glyphRangeForTextContainer:textContainer];
|
||||||
[layoutManager drawBackgroundForGlyphRange:glyphRange atPoint:shadowInsetBounds.origin];
|
[layoutManager drawBackgroundForGlyphRange:glyphRange atPoint:shadowInsetBounds.origin];
|
||||||
[layoutManager drawGlyphsForGlyphRange:glyphRange atPoint:shadowInsetBounds.origin];
|
[layoutManager drawGlyphsForGlyphRange:glyphRange atPoint:shadowInsetBounds.origin];
|
||||||
@@ -125,7 +151,7 @@ static NSCharacterSet *_defaultAvoidTruncationCharacterSet()
|
|||||||
- (NSUInteger)lineCount
|
- (NSUInteger)lineCount
|
||||||
{
|
{
|
||||||
__block NSUInteger lineCount = 0;
|
__block NSUInteger lineCount = 0;
|
||||||
[_context performBlockWithLockedTextKitComponents:^(NSLayoutManager *layoutManager, NSTextStorage *textStorage, NSTextContainer *textContainer) {
|
[[self context] performBlockWithLockedTextKitComponents:^(NSLayoutManager *layoutManager, NSTextStorage *textStorage, NSTextContainer *textContainer) {
|
||||||
for (NSRange lineRange = { 0, 0 }; NSMaxRange(lineRange) < [layoutManager numberOfGlyphs]; lineCount++) {
|
for (NSRange lineRange = { 0, 0 }; NSMaxRange(lineRange) < [layoutManager numberOfGlyphs]; lineCount++) {
|
||||||
[layoutManager lineFragmentRectForGlyphAtIndex:NSMaxRange(lineRange) effectiveRange:&lineRange];
|
[layoutManager lineFragmentRectForGlyphAtIndex:NSMaxRange(lineRange) effectiveRange:&lineRange];
|
||||||
}
|
}
|
||||||
@@ -135,7 +161,7 @@ static NSCharacterSet *_defaultAvoidTruncationCharacterSet()
|
|||||||
|
|
||||||
- (std::vector<NSRange>)visibleRanges
|
- (std::vector<NSRange>)visibleRanges
|
||||||
{
|
{
|
||||||
return _truncater.visibleRanges;
|
return [self truncater].visibleRanges;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// ASBasicImageDownloaderTests.m
|
// ASZBasicImageDownloaderTests.m
|
||||||
// AsyncDisplayKit
|
// AsyncDisplayKit
|
||||||
//
|
//
|
||||||
// Created by Victor Mayorov on 10/06/15.
|
// Created by Victor Mayorov on 10/06/15.
|
||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#import <AsyncDisplayKit/ASBasicImageDownloader.h>
|
#import <AsyncDisplayKit/ASBasicImageDownloader.h>
|
||||||
|
|
||||||
|
// Z in the name to delay running until after the test instance is operating normally.
|
||||||
@interface ASBasicImageDownloaderTests : XCTestCase
|
@interface ASBasicImageDownloaderTests : XCTestCase
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -21,34 +22,27 @@
|
|||||||
ASBasicImageDownloader *downloader = [ASBasicImageDownloader sharedImageDownloader];
|
ASBasicImageDownloader *downloader = [ASBasicImageDownloader sharedImageDownloader];
|
||||||
|
|
||||||
NSURL *URL = [NSURL URLWithString:@"http://wrongPath/wrongResource.png"];
|
NSURL *URL = [NSURL URLWithString:@"http://wrongPath/wrongResource.png"];
|
||||||
|
|
||||||
dispatch_group_t group = dispatch_group_create();
|
|
||||||
|
|
||||||
__block BOOL firstDone = NO;
|
__block BOOL firstDone = NO;
|
||||||
|
|
||||||
dispatch_group_enter(group);
|
|
||||||
[downloader downloadImageWithURL:URL
|
[downloader downloadImageWithURL:URL
|
||||||
callbackQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
|
callbackQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
|
||||||
downloadProgressBlock:nil
|
downloadProgressBlock:nil
|
||||||
completion:^(CGImageRef image, NSError *error) {
|
completion:^(CGImageRef image, NSError *error) {
|
||||||
firstDone = YES;
|
firstDone = YES;
|
||||||
dispatch_group_leave(group);
|
|
||||||
}];
|
}];
|
||||||
|
|
||||||
__block BOOL secondDone = NO;
|
__block BOOL secondDone = NO;
|
||||||
|
|
||||||
dispatch_group_enter(group);
|
|
||||||
[downloader downloadImageWithURL:URL
|
[downloader downloadImageWithURL:URL
|
||||||
callbackQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
|
callbackQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
|
||||||
downloadProgressBlock:nil
|
downloadProgressBlock:nil
|
||||||
completion:^(CGImageRef image, NSError *error) {
|
completion:^(CGImageRef image, NSError *error) {
|
||||||
secondDone = YES;
|
secondDone = YES;
|
||||||
dispatch_group_leave(group);
|
|
||||||
}];
|
}];
|
||||||
|
|
||||||
XCTAssert(0 == dispatch_group_wait(group, dispatch_time(0, 10 * 1000000000)), @"URL loading takes too long");
|
sleep(3);
|
||||||
|
XCTAssert(firstDone && secondDone, @"Not all ASBasicImageDownloader completion handlers have been called after 3 seconds");
|
||||||
XCTAssert(firstDone && secondDone, @"Not all handlers has been called");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -100,7 +100,7 @@
|
|||||||
layout.scrollDirection = UICollectionViewScrollDirectionVertical;
|
layout.scrollDirection = UICollectionViewScrollDirectionVertical;
|
||||||
|
|
||||||
CGRect rect = CGRectMake(0, 0, 100.0, 100.0);
|
CGRect rect = CGRectMake(0, 0, 100.0, 100.0);
|
||||||
ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:rect collectionViewLayout:layout asyncDataFetching:NO];
|
ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:rect collectionViewLayout:layout];
|
||||||
collectionView.asyncDataSource = dataSource;
|
collectionView.asyncDataSource = dataSource;
|
||||||
collectionView.asyncDelegate = delegate;
|
collectionView.asyncDelegate = delegate;
|
||||||
|
|
||||||
@@ -122,7 +122,7 @@
|
|||||||
layout.scrollDirection = UICollectionViewScrollDirectionVertical;
|
layout.scrollDirection = UICollectionViewScrollDirectionVertical;
|
||||||
|
|
||||||
CGRect rect = CGRectMake(0, 0, 100.0, 100.0);
|
CGRect rect = CGRectMake(0, 0, 100.0, 100.0);
|
||||||
ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:rect collectionViewLayout:layout asyncDataFetching:NO];
|
ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:rect collectionViewLayout:layout];
|
||||||
collectionView.asyncDataSource = dataSource;
|
collectionView.asyncDataSource = dataSource;
|
||||||
collectionView.asyncDelegate = delegate;
|
collectionView.asyncDelegate = delegate;
|
||||||
|
|
||||||
@@ -146,7 +146,7 @@
|
|||||||
layout.headerReferenceSize = CGSizeMake(125.0, 125.0);
|
layout.headerReferenceSize = CGSizeMake(125.0, 125.0);
|
||||||
|
|
||||||
CGRect rect = CGRectMake(0, 0, 100.0, 100.0);
|
CGRect rect = CGRectMake(0, 0, 100.0, 100.0);
|
||||||
ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:rect collectionViewLayout:layout asyncDataFetching:NO];
|
ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:rect collectionViewLayout:layout];
|
||||||
collectionView.asyncDataSource = dataSource;
|
collectionView.asyncDataSource = dataSource;
|
||||||
|
|
||||||
ASCollectionViewFlowLayoutInspector *inspector = [[ASCollectionViewFlowLayoutInspector alloc] initWithCollectionView:collectionView flowLayout:layout];
|
ASCollectionViewFlowLayoutInspector *inspector = [[ASCollectionViewFlowLayoutInspector alloc] initWithCollectionView:collectionView flowLayout:layout];
|
||||||
@@ -167,7 +167,7 @@
|
|||||||
layout.footerReferenceSize = CGSizeMake(125.0, 125.0);
|
layout.footerReferenceSize = CGSizeMake(125.0, 125.0);
|
||||||
|
|
||||||
CGRect rect = CGRectMake(0, 0, 100.0, 100.0);
|
CGRect rect = CGRectMake(0, 0, 100.0, 100.0);
|
||||||
ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:rect collectionViewLayout:layout asyncDataFetching:NO];
|
ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:rect collectionViewLayout:layout];
|
||||||
collectionView.asyncDataSource = dataSource;
|
collectionView.asyncDataSource = dataSource;
|
||||||
|
|
||||||
ASCollectionViewFlowLayoutInspector *inspector = [[ASCollectionViewFlowLayoutInspector alloc] initWithCollectionView:collectionView flowLayout:layout];
|
ASCollectionViewFlowLayoutInspector *inspector = [[ASCollectionViewFlowLayoutInspector alloc] initWithCollectionView:collectionView flowLayout:layout];
|
||||||
@@ -190,7 +190,7 @@
|
|||||||
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
|
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
|
||||||
|
|
||||||
CGRect rect = CGRectMake(0, 0, 100.0, 100.0);
|
CGRect rect = CGRectMake(0, 0, 100.0, 100.0);
|
||||||
ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:rect collectionViewLayout:layout asyncDataFetching:NO];
|
ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:rect collectionViewLayout:layout];
|
||||||
collectionView.asyncDataSource = dataSource;
|
collectionView.asyncDataSource = dataSource;
|
||||||
collectionView.asyncDelegate = delegate;
|
collectionView.asyncDelegate = delegate;
|
||||||
|
|
||||||
@@ -212,7 +212,7 @@
|
|||||||
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
|
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
|
||||||
|
|
||||||
CGRect rect = CGRectMake(0, 0, 100.0, 100.0);
|
CGRect rect = CGRectMake(0, 0, 100.0, 100.0);
|
||||||
ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:rect collectionViewLayout:layout asyncDataFetching:NO];
|
ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:rect collectionViewLayout:layout];
|
||||||
collectionView.asyncDataSource = dataSource;
|
collectionView.asyncDataSource = dataSource;
|
||||||
collectionView.asyncDelegate = delegate;
|
collectionView.asyncDelegate = delegate;
|
||||||
|
|
||||||
@@ -236,7 +236,7 @@
|
|||||||
layout.headerReferenceSize = CGSizeMake(125.0, 125.0);
|
layout.headerReferenceSize = CGSizeMake(125.0, 125.0);
|
||||||
|
|
||||||
CGRect rect = CGRectMake(0, 0, 100.0, 100.0);
|
CGRect rect = CGRectMake(0, 0, 100.0, 100.0);
|
||||||
ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:rect collectionViewLayout:layout asyncDataFetching:NO];
|
ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:rect collectionViewLayout:layout];
|
||||||
collectionView.asyncDataSource = dataSource;
|
collectionView.asyncDataSource = dataSource;
|
||||||
|
|
||||||
ASCollectionViewFlowLayoutInspector *inspector = [[ASCollectionViewFlowLayoutInspector alloc] initWithCollectionView:collectionView flowLayout:layout];
|
ASCollectionViewFlowLayoutInspector *inspector = [[ASCollectionViewFlowLayoutInspector alloc] initWithCollectionView:collectionView flowLayout:layout];
|
||||||
@@ -257,7 +257,7 @@
|
|||||||
layout.footerReferenceSize = CGSizeMake(125.0, 125.0);
|
layout.footerReferenceSize = CGSizeMake(125.0, 125.0);
|
||||||
|
|
||||||
CGRect rect = CGRectMake(0, 0, 100.0, 100.0);
|
CGRect rect = CGRectMake(0, 0, 100.0, 100.0);
|
||||||
ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:rect collectionViewLayout:layout asyncDataFetching:NO];
|
ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:rect collectionViewLayout:layout];
|
||||||
collectionView.asyncDataSource = dataSource;
|
collectionView.asyncDataSource = dataSource;
|
||||||
|
|
||||||
ASCollectionViewFlowLayoutInspector *inspector = [[ASCollectionViewFlowLayoutInspector alloc] initWithCollectionView:collectionView flowLayout:layout];
|
ASCollectionViewFlowLayoutInspector *inspector = [[ASCollectionViewFlowLayoutInspector alloc] initWithCollectionView:collectionView flowLayout:layout];
|
||||||
@@ -274,7 +274,7 @@
|
|||||||
InspectorTestDataSource *dataSource = [[InspectorTestDataSource alloc] init];
|
InspectorTestDataSource *dataSource = [[InspectorTestDataSource alloc] init];
|
||||||
HeaderReferenceSizeTestDelegate *delegate = [[HeaderReferenceSizeTestDelegate alloc] init];
|
HeaderReferenceSizeTestDelegate *delegate = [[HeaderReferenceSizeTestDelegate alloc] init];
|
||||||
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
|
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
|
||||||
ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout asyncDataFetching:NO];
|
ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
|
||||||
collectionView.asyncDataSource = dataSource;
|
collectionView.asyncDataSource = dataSource;
|
||||||
collectionView.asyncDelegate = delegate;
|
collectionView.asyncDelegate = delegate;
|
||||||
ASCollectionViewFlowLayoutInspector *inspector = [[ASCollectionViewFlowLayoutInspector alloc] initWithCollectionView:collectionView flowLayout:layout];
|
ASCollectionViewFlowLayoutInspector *inspector = [[ASCollectionViewFlowLayoutInspector alloc] initWithCollectionView:collectionView flowLayout:layout];
|
||||||
@@ -291,7 +291,7 @@
|
|||||||
- (void)testThatItRespondsWithTheDefaultNumberOfSections
|
- (void)testThatItRespondsWithTheDefaultNumberOfSections
|
||||||
{
|
{
|
||||||
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
|
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
|
||||||
ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout asyncDataFetching:NO];
|
ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
|
||||||
ASCollectionViewFlowLayoutInspector *inspector = [[ASCollectionViewFlowLayoutInspector alloc] initWithCollectionView:collectionView flowLayout:layout];
|
ASCollectionViewFlowLayoutInspector *inspector = [[ASCollectionViewFlowLayoutInspector alloc] initWithCollectionView:collectionView flowLayout:layout];
|
||||||
NSUInteger sections = [inspector collectionView:collectionView numberOfSectionsForSupplementaryNodeOfKind:UICollectionElementKindSectionHeader];
|
NSUInteger sections = [inspector collectionView:collectionView numberOfSectionsForSupplementaryNodeOfKind:UICollectionElementKindSectionHeader];
|
||||||
XCTAssert(sections == 1, @"should return 1 by default");
|
XCTAssert(sections == 1, @"should return 1 by default");
|
||||||
@@ -304,7 +304,7 @@
|
|||||||
{
|
{
|
||||||
InspectorTestDataSource *dataSource = [[InspectorTestDataSource alloc] init];
|
InspectorTestDataSource *dataSource = [[InspectorTestDataSource alloc] init];
|
||||||
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
|
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
|
||||||
ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout asyncDataFetching:NO];
|
ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
|
||||||
collectionView.asyncDataSource = dataSource;
|
collectionView.asyncDataSource = dataSource;
|
||||||
ASCollectionViewFlowLayoutInspector *inspector = [[ASCollectionViewFlowLayoutInspector alloc] initWithCollectionView:collectionView flowLayout:layout];
|
ASCollectionViewFlowLayoutInspector *inspector = [[ASCollectionViewFlowLayoutInspector alloc] initWithCollectionView:collectionView flowLayout:layout];
|
||||||
NSUInteger sections = [inspector collectionView:collectionView numberOfSectionsForSupplementaryNodeOfKind:UICollectionElementKindSectionHeader];
|
NSUInteger sections = [inspector collectionView:collectionView numberOfSectionsForSupplementaryNodeOfKind:UICollectionElementKindSectionHeader];
|
||||||
@@ -321,7 +321,7 @@
|
|||||||
InspectorTestDataSource *dataSource = [[InspectorTestDataSource alloc] init];
|
InspectorTestDataSource *dataSource = [[InspectorTestDataSource alloc] init];
|
||||||
HeaderReferenceSizeTestDelegate *delegate = [[HeaderReferenceSizeTestDelegate alloc] init];
|
HeaderReferenceSizeTestDelegate *delegate = [[HeaderReferenceSizeTestDelegate alloc] init];
|
||||||
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
|
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
|
||||||
ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout asyncDataFetching:NO];
|
ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
|
||||||
collectionView.asyncDataSource = dataSource;
|
collectionView.asyncDataSource = dataSource;
|
||||||
collectionView.asyncDelegate = delegate;
|
collectionView.asyncDelegate = delegate;
|
||||||
ASCollectionViewFlowLayoutInspector *inspector = [[ASCollectionViewFlowLayoutInspector alloc] initWithCollectionView:collectionView flowLayout:layout];
|
ASCollectionViewFlowLayoutInspector *inspector = [[ASCollectionViewFlowLayoutInspector alloc] initWithCollectionView:collectionView flowLayout:layout];
|
||||||
@@ -338,7 +338,7 @@
|
|||||||
HeaderReferenceSizeTestDelegate *delegate = [[HeaderReferenceSizeTestDelegate alloc] init];
|
HeaderReferenceSizeTestDelegate *delegate = [[HeaderReferenceSizeTestDelegate alloc] init];
|
||||||
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
|
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
|
||||||
layout.footerReferenceSize = CGSizeMake(125.0, 125.0);
|
layout.footerReferenceSize = CGSizeMake(125.0, 125.0);
|
||||||
ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout asyncDataFetching:NO];
|
ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
|
||||||
collectionView.asyncDataSource = dataSource;
|
collectionView.asyncDataSource = dataSource;
|
||||||
collectionView.asyncDelegate = delegate;
|
collectionView.asyncDelegate = delegate;
|
||||||
ASCollectionViewFlowLayoutInspector *inspector = [[ASCollectionViewFlowLayoutInspector alloc] initWithCollectionView:collectionView flowLayout:layout];
|
ASCollectionViewFlowLayoutInspector *inspector = [[ASCollectionViewFlowLayoutInspector alloc] initWithCollectionView:collectionView flowLayout:layout];
|
||||||
@@ -354,7 +354,7 @@
|
|||||||
InspectorTestDataSource *dataSource = [[InspectorTestDataSource alloc] init];
|
InspectorTestDataSource *dataSource = [[InspectorTestDataSource alloc] init];
|
||||||
HeaderReferenceSizeTestDelegate *delegate = [[HeaderReferenceSizeTestDelegate alloc] init];
|
HeaderReferenceSizeTestDelegate *delegate = [[HeaderReferenceSizeTestDelegate alloc] init];
|
||||||
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
|
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
|
||||||
ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout asyncDataFetching:NO];
|
ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
|
||||||
collectionView.asyncDataSource = dataSource;
|
collectionView.asyncDataSource = dataSource;
|
||||||
collectionView.asyncDelegate = delegate;
|
collectionView.asyncDelegate = delegate;
|
||||||
ASCollectionViewFlowLayoutInspector *inspector = [[ASCollectionViewFlowLayoutInspector alloc] initWithCollectionView:collectionView flowLayout:layout];
|
ASCollectionViewFlowLayoutInspector *inspector = [[ASCollectionViewFlowLayoutInspector alloc] initWithCollectionView:collectionView flowLayout:layout];
|
||||||
|
|||||||
@@ -52,7 +52,6 @@
|
|||||||
if (_willDeallocBlock) {
|
if (_willDeallocBlock) {
|
||||||
_willDeallocBlock(self);
|
_willDeallocBlock(self);
|
||||||
}
|
}
|
||||||
[super dealloc];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -78,7 +77,6 @@
|
|||||||
if (_willDeallocBlock) {
|
if (_willDeallocBlock) {
|
||||||
_willDeallocBlock(self);
|
_willDeallocBlock(self);
|
||||||
}
|
}
|
||||||
[super dealloc];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -130,6 +128,7 @@
|
|||||||
|
|
||||||
@implementation ASTableViewTests
|
@implementation ASTableViewTests
|
||||||
|
|
||||||
|
// TODO: Convert this to ARC.
|
||||||
- (void)DISABLED_testTableViewDoesNotRetainItselfAndDelegate
|
- (void)DISABLED_testTableViewDoesNotRetainItselfAndDelegate
|
||||||
{
|
{
|
||||||
ASTestTableView *tableView = [[ASTestTableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
|
ASTestTableView *tableView = [[ASTestTableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
|
||||||
@@ -148,11 +147,11 @@
|
|||||||
|
|
||||||
tableView.asyncDataSource = delegate;
|
tableView.asyncDataSource = delegate;
|
||||||
tableView.asyncDelegate = delegate;
|
tableView.asyncDelegate = delegate;
|
||||||
|
|
||||||
[delegate release];
|
// [delegate release];
|
||||||
XCTAssertTrue(delegateDidDealloc, @"unexpected delegate lifetime:%@", delegate);
|
XCTAssertTrue(delegateDidDealloc, @"unexpected delegate lifetime:%@", delegate);
|
||||||
|
|
||||||
XCTAssertNoThrow([tableView release], @"unexpected exception when deallocating table view:%@", tableView);
|
// XCTAssertNoThrow([tableView release], @"unexpected exception when deallocating table view:%@", tableView);
|
||||||
XCTAssertTrue(tableViewDidDealloc, @"unexpected table view lifetime:%@", tableView);
|
XCTAssertTrue(tableViewDidDealloc, @"unexpected table view lifetime:%@", tableView);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -399,7 +398,10 @@
|
|||||||
style:UITableViewStylePlain
|
style:UITableViewStylePlain
|
||||||
asyncDataFetching:YES];
|
asyncDataFetching:YES];
|
||||||
ASTableViewFilledDataSource *dataSource = [ASTableViewFilledDataSource new];
|
ASTableViewFilledDataSource *dataSource = [ASTableViewFilledDataSource new];
|
||||||
|
#if ! __has_feature(objc_arc)
|
||||||
|
#error This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
|
||||||
|
#endif
|
||||||
|
|
||||||
tableView.asyncDelegate = dataSource;
|
tableView.asyncDelegate = dataSource;
|
||||||
tableView.asyncDataSource = dataSource;
|
tableView.asyncDataSource = dataSource;
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
AC3C4A6A1A11F47200143C57 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = AC3C4A691A11F47200143C57 /* ViewController.m */; };
|
AC3C4A6A1A11F47200143C57 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = AC3C4A691A11F47200143C57 /* ViewController.m */; };
|
||||||
AC3C4A8E1A11F80C00143C57 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AC3C4A8D1A11F80C00143C57 /* Images.xcassets */; };
|
AC3C4A8E1A11F80C00143C57 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AC3C4A8D1A11F80C00143C57 /* Images.xcassets */; };
|
||||||
FABD6D156A3EB118497E5CE6 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F02BAF78E68BC56FD8C161B7 /* libPods.a */; };
|
FABD6D156A3EB118497E5CE6 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F02BAF78E68BC56FD8C161B7 /* libPods.a */; };
|
||||||
|
FC3FCA801C2B1564009F6D6D /* PresentingViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FC3FCA7F1C2B1564009F6D6D /* PresentingViewController.m */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
@@ -34,6 +35,8 @@
|
|||||||
AC3C4A8D1A11F80C00143C57 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
|
AC3C4A8D1A11F80C00143C57 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
|
||||||
CD1ABB23007FEDB31D8C1978 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = "<group>"; };
|
CD1ABB23007FEDB31D8C1978 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
F02BAF78E68BC56FD8C161B7 /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
F02BAF78E68BC56FD8C161B7 /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
FC3FCA7E1C2B1564009F6D6D /* PresentingViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PresentingViewController.h; sourceTree = "<group>"; };
|
||||||
|
FC3FCA7F1C2B1564009F6D6D /* PresentingViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PresentingViewController.m; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
@@ -82,6 +85,8 @@
|
|||||||
AC3C4A661A11F47200143C57 /* AppDelegate.m */,
|
AC3C4A661A11F47200143C57 /* AppDelegate.m */,
|
||||||
AC3C4A681A11F47200143C57 /* ViewController.h */,
|
AC3C4A681A11F47200143C57 /* ViewController.h */,
|
||||||
AC3C4A691A11F47200143C57 /* ViewController.m */,
|
AC3C4A691A11F47200143C57 /* ViewController.m */,
|
||||||
|
FC3FCA7E1C2B1564009F6D6D /* PresentingViewController.h */,
|
||||||
|
FC3FCA7F1C2B1564009F6D6D /* PresentingViewController.m */,
|
||||||
AC3C4A8D1A11F80C00143C57 /* Images.xcassets */,
|
AC3C4A8D1A11F80C00143C57 /* Images.xcassets */,
|
||||||
AC3C4A611A11F47200143C57 /* Supporting Files */,
|
AC3C4A611A11F47200143C57 /* Supporting Files */,
|
||||||
9B92C87F1BC17D3000EE46B2 /* SupplementaryNode.h */,
|
9B92C87F1BC17D3000EE46B2 /* SupplementaryNode.h */,
|
||||||
@@ -125,7 +130,6 @@
|
|||||||
AC3C4A5B1A11F47200143C57 /* Frameworks */,
|
AC3C4A5B1A11F47200143C57 /* Frameworks */,
|
||||||
AC3C4A5C1A11F47200143C57 /* Resources */,
|
AC3C4A5C1A11F47200143C57 /* Resources */,
|
||||||
A6902C454C7661D0D277AC62 /* Copy Pods Resources */,
|
A6902C454C7661D0D277AC62 /* Copy Pods Resources */,
|
||||||
EC37EEC9933F5786936BFE7C /* Embed Pods Frameworks */,
|
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
@@ -196,21 +200,6 @@
|
|||||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n";
|
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n";
|
||||||
showEnvVarsInLog = 0;
|
showEnvVarsInLog = 0;
|
||||||
};
|
};
|
||||||
EC37EEC9933F5786936BFE7C /* Embed Pods Frameworks */ = {
|
|
||||||
isa = PBXShellScriptBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
inputPaths = (
|
|
||||||
);
|
|
||||||
name = "Embed Pods Frameworks";
|
|
||||||
outputPaths = (
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
shellPath = /bin/sh;
|
|
||||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-frameworks.sh\"\n";
|
|
||||||
showEnvVarsInLog = 0;
|
|
||||||
};
|
|
||||||
F868CFBB21824CC9521B6588 /* Check Pods Manifest.lock */ = {
|
F868CFBB21824CC9521B6588 /* Check Pods Manifest.lock */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
@@ -236,6 +225,7 @@
|
|||||||
25FDEC921BF31EE700CEB123 /* ItemNode.m in Sources */,
|
25FDEC921BF31EE700CEB123 /* ItemNode.m in Sources */,
|
||||||
AC3C4A6A1A11F47200143C57 /* ViewController.m in Sources */,
|
AC3C4A6A1A11F47200143C57 /* ViewController.m in Sources */,
|
||||||
9B92C8811BC17D3000EE46B2 /* SupplementaryNode.m in Sources */,
|
9B92C8811BC17D3000EE46B2 /* SupplementaryNode.m in Sources */,
|
||||||
|
FC3FCA801C2B1564009F6D6D /* PresentingViewController.m in Sources */,
|
||||||
AC3C4A671A11F47200143C57 /* AppDelegate.m in Sources */,
|
AC3C4A671A11F47200143C57 /* AppDelegate.m in Sources */,
|
||||||
AC3C4A641A11F47200143C57 /* main.m in Sources */,
|
AC3C4A641A11F47200143C57 /* main.m in Sources */,
|
||||||
);
|
);
|
||||||
|
|||||||
10
examples/ASCollectionView/Sample.xcworkspace/contents.xcworkspacedata
generated
Normal file
10
examples/ASCollectionView/Sample.xcworkspace/contents.xcworkspacedata
generated
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Workspace
|
||||||
|
version = "1.0">
|
||||||
|
<FileRef
|
||||||
|
location = "group:Sample.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
|
<FileRef
|
||||||
|
location = "group:Pods/Pods.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
|
</Workspace>
|
||||||
@@ -11,6 +11,8 @@
|
|||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
#define SIMULATE_WEB_RESPONSE 0
|
||||||
|
|
||||||
@interface AppDelegate : UIResponder <UIApplicationDelegate>
|
@interface AppDelegate : UIResponder <UIApplicationDelegate>
|
||||||
|
|
||||||
@property (strong, nonatomic) UIWindow *window;
|
@property (strong, nonatomic) UIWindow *window;
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#import "AppDelegate.h"
|
#import "AppDelegate.h"
|
||||||
|
|
||||||
|
#import "PresentingViewController.h"
|
||||||
#import "ViewController.h"
|
#import "ViewController.h"
|
||||||
|
|
||||||
@implementation AppDelegate
|
@implementation AppDelegate
|
||||||
@@ -31,10 +32,14 @@
|
|||||||
- (void)pushNewViewControllerAnimated:(BOOL)animated
|
- (void)pushNewViewControllerAnimated:(BOOL)animated
|
||||||
{
|
{
|
||||||
UINavigationController *navController = (UINavigationController *)self.window.rootViewController;
|
UINavigationController *navController = (UINavigationController *)self.window.rootViewController;
|
||||||
|
|
||||||
|
#if SIMULATE_WEB_RESPONSE
|
||||||
|
UIViewController *viewController = [[PresentingViewController alloc] init];
|
||||||
|
#else
|
||||||
UIViewController *viewController = [[ViewController alloc] init];
|
UIViewController *viewController = [[ViewController alloc] init];
|
||||||
viewController.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Push Another Copy" style:UIBarButtonItemStylePlain target:self action:@selector(pushNewViewController)];
|
viewController.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Push Another Copy" style:UIBarButtonItemStylePlain target:self action:@selector(pushNewViewController)];
|
||||||
|
#endif
|
||||||
|
|
||||||
[navController pushViewController:viewController animated:animated];
|
[navController pushViewController:viewController animated:animated];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
13
examples/ASCollectionView/Sample/PresentingViewController.h
Normal file
13
examples/ASCollectionView/Sample/PresentingViewController.h
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
//
|
||||||
|
// PresentingViewController.h
|
||||||
|
// Sample
|
||||||
|
//
|
||||||
|
// Created by Tom King on 12/23/15.
|
||||||
|
// Copyright © 2015 Facebook. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
@interface PresentingViewController : UIViewController
|
||||||
|
|
||||||
|
@end
|
||||||
30
examples/ASCollectionView/Sample/PresentingViewController.m
Normal file
30
examples/ASCollectionView/Sample/PresentingViewController.m
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
//
|
||||||
|
// PresentingViewController.m
|
||||||
|
// Sample
|
||||||
|
//
|
||||||
|
// Created by Tom King on 12/23/15.
|
||||||
|
// Copyright © 2015 Facebook. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "PresentingViewController.h"
|
||||||
|
#import "ViewController.h"
|
||||||
|
|
||||||
|
@interface PresentingViewController ()
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation PresentingViewController
|
||||||
|
|
||||||
|
- (void)viewDidLoad
|
||||||
|
{
|
||||||
|
[super viewDidLoad];
|
||||||
|
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Push Details" style:UIBarButtonItemStylePlain target:self action:@selector(pushNewViewController)];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)pushNewViewController
|
||||||
|
{
|
||||||
|
ViewController *controller = [[ViewController alloc] init];
|
||||||
|
[self.navigationController pushViewController:controller animated:true];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -18,6 +18,7 @@
|
|||||||
@interface ViewController () <ASCollectionViewDataSource, ASCollectionViewDelegateFlowLayout>
|
@interface ViewController () <ASCollectionViewDataSource, ASCollectionViewDelegateFlowLayout>
|
||||||
{
|
{
|
||||||
ASCollectionView *_collectionView;
|
ASCollectionView *_collectionView;
|
||||||
|
NSArray *_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -37,7 +38,7 @@
|
|||||||
layout.headerReferenceSize = CGSizeMake(50.0, 50.0);
|
layout.headerReferenceSize = CGSizeMake(50.0, 50.0);
|
||||||
layout.footerReferenceSize = CGSizeMake(50.0, 50.0);
|
layout.footerReferenceSize = CGSizeMake(50.0, 50.0);
|
||||||
|
|
||||||
_collectionView = [[ASCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout asyncDataFetching:YES];
|
_collectionView = [[ASCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
|
||||||
_collectionView.asyncDataSource = self;
|
_collectionView.asyncDataSource = self;
|
||||||
_collectionView.asyncDelegate = self;
|
_collectionView.asyncDelegate = self;
|
||||||
_collectionView.backgroundColor = [UIColor whiteColor];
|
_collectionView.backgroundColor = [UIColor whiteColor];
|
||||||
@@ -45,8 +46,10 @@
|
|||||||
[_collectionView registerSupplementaryNodeOfKind:UICollectionElementKindSectionHeader];
|
[_collectionView registerSupplementaryNodeOfKind:UICollectionElementKindSectionHeader];
|
||||||
[_collectionView registerSupplementaryNodeOfKind:UICollectionElementKindSectionFooter];
|
[_collectionView registerSupplementaryNodeOfKind:UICollectionElementKindSectionFooter];
|
||||||
|
|
||||||
|
#if !SIMULATE_WEB_RESPONSE
|
||||||
self.navigationItem.leftItemsSupplementBackButton = YES;
|
self.navigationItem.leftItemsSupplementBackButton = YES;
|
||||||
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh target:self action:@selector(reloadTapped)];
|
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh target:self action:@selector(reloadTapped)];
|
||||||
|
#endif
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@@ -56,6 +59,31 @@
|
|||||||
[super viewDidLoad];
|
[super viewDidLoad];
|
||||||
|
|
||||||
[self.view addSubview:_collectionView];
|
[self.view addSubview:_collectionView];
|
||||||
|
|
||||||
|
#if SIMULATE_WEB_RESPONSE
|
||||||
|
__weak typeof(self) weakSelf = self;
|
||||||
|
void(^mockWebService)() = ^{
|
||||||
|
NSLog(@"ViewController \"got data from a web service\"");
|
||||||
|
ViewController *strongSelf = weakSelf;
|
||||||
|
if (strongSelf != nil)
|
||||||
|
{
|
||||||
|
NSLog(@"ViewController is not nil");
|
||||||
|
strongSelf->_data = [[NSArray alloc] init];
|
||||||
|
[strongSelf->_collectionView performBatchUpdates:^{
|
||||||
|
[strongSelf->_collectionView insertSections:[[NSIndexSet alloc] initWithIndexesInRange:NSMakeRange(0, 100)]];
|
||||||
|
} completion:nil];
|
||||||
|
NSLog(@"ViewController finished updating collectionView");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
NSLog(@"ViewController is nil - won't update collectionView");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), mockWebService);
|
||||||
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||||
|
[self.navigationController popViewControllerAnimated:YES];
|
||||||
|
});
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)viewWillLayoutSubviews
|
- (void)viewWillLayoutSubviews
|
||||||
@@ -101,7 +129,11 @@
|
|||||||
|
|
||||||
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
|
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
|
||||||
{
|
{
|
||||||
|
#if SIMULATE_WEB_RESPONSE
|
||||||
|
return _data == nil ? 0 : 100;
|
||||||
|
#else
|
||||||
return 100;
|
return 100;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)collectionViewLockDataSource:(ASCollectionView *)collectionView
|
- (void)collectionViewLockDataSource:(ASCollectionView *)collectionView
|
||||||
@@ -125,4 +157,11 @@
|
|||||||
return UIEdgeInsetsMake(20.0, 20.0, 20.0, 20.0);
|
return UIEdgeInsetsMake(20.0, 20.0, 20.0, 20.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SIMULATE_WEB_RESPONSE
|
||||||
|
-(void)dealloc
|
||||||
|
{
|
||||||
|
NSLog(@"ViewController is deallocing");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -130,7 +130,6 @@
|
|||||||
AC3C4A5B1A11F47200143C57 /* Frameworks */,
|
AC3C4A5B1A11F47200143C57 /* Frameworks */,
|
||||||
AC3C4A5C1A11F47200143C57 /* Resources */,
|
AC3C4A5C1A11F47200143C57 /* Resources */,
|
||||||
A6902C454C7661D0D277AC62 /* Copy Pods Resources */,
|
A6902C454C7661D0D277AC62 /* Copy Pods Resources */,
|
||||||
EC37EEC9933F5786936BFE7C /* Embed Pods Frameworks */,
|
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
@@ -201,21 +200,6 @@
|
|||||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n";
|
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n";
|
||||||
showEnvVarsInLog = 0;
|
showEnvVarsInLog = 0;
|
||||||
};
|
};
|
||||||
EC37EEC9933F5786936BFE7C /* Embed Pods Frameworks */ = {
|
|
||||||
isa = PBXShellScriptBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
inputPaths = (
|
|
||||||
);
|
|
||||||
name = "Embed Pods Frameworks";
|
|
||||||
outputPaths = (
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
shellPath = /bin/sh;
|
|
||||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-frameworks.sh\"\n";
|
|
||||||
showEnvVarsInLog = 0;
|
|
||||||
};
|
|
||||||
F868CFBB21824CC9521B6588 /* Check Pods Manifest.lock */ = {
|
F868CFBB21824CC9521B6588 /* Check Pods Manifest.lock */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
|
|||||||
Reference in New Issue
Block a user