diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index 5781496c5c..4995f00798 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -407,6 +407,10 @@ 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 */; }; DB7121BCD50849C498C886FB /* libPods-AsyncDisplayKitTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = EFA731F0396842FF8AB635EE /* libPods-AsyncDisplayKitTests.a */; }; + DE6D9E321C0AD9ED001A1DD3 /* ASRangeHandlerVisible.h in Headers */ = {isa = PBXBuildFile; fileRef = DE6D9E301C0AD9ED001A1DD3 /* ASRangeHandlerVisible.h */; }; + DE6D9E331C0AD9ED001A1DD3 /* ASRangeHandlerVisible.h in Headers */ = {isa = PBXBuildFile; fileRef = DE6D9E301C0AD9ED001A1DD3 /* ASRangeHandlerVisible.h */; }; + DE6D9E341C0AD9ED001A1DD3 /* ASRangeHandlerVisible.mm in Sources */ = {isa = PBXBuildFile; fileRef = DE6D9E311C0AD9ED001A1DD3 /* ASRangeHandlerVisible.mm */; }; + DE6D9E351C0AD9ED001A1DD3 /* ASRangeHandlerVisible.mm in Sources */ = {isa = PBXBuildFile; fileRef = DE6D9E311C0AD9ED001A1DD3 /* ASRangeHandlerVisible.mm */; }; 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, ); }; }; DECBD6E91BE56E1900CF4905 /* ASButtonNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = DECBD6E61BE56E1900CF4905 /* ASButtonNode.mm */; }; @@ -675,6 +679,8 @@ D3779BCFF841AD3EB56537ED /* Pods-AsyncDisplayKitTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AsyncDisplayKitTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-AsyncDisplayKitTests/Pods-AsyncDisplayKitTests.release.xcconfig"; sourceTree = ""; }; D785F6601A74327E00291744 /* ASScrollNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASScrollNode.h; sourceTree = ""; }; D785F6611A74327E00291744 /* ASScrollNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASScrollNode.m; sourceTree = ""; }; + DE6D9E301C0AD9ED001A1DD3 /* ASRangeHandlerVisible.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASRangeHandlerVisible.h; sourceTree = ""; }; + DE6D9E311C0AD9ED001A1DD3 /* ASRangeHandlerVisible.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASRangeHandlerVisible.mm; sourceTree = ""; }; DECBD6E51BE56E1900CF4905 /* ASButtonNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASButtonNode.h; sourceTree = ""; }; DECBD6E61BE56E1900CF4905 /* ASButtonNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASButtonNode.mm; sourceTree = ""; }; EFA731F0396842FF8AB635EE /* libPods-AsyncDisplayKitTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-AsyncDisplayKitTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -938,6 +944,8 @@ 055F1A3619ABD413004DAFF1 /* ASRangeController.h */, 055F1A3719ABD413004DAFF1 /* ASRangeController.mm */, 292C599C1A956527007E5DD6 /* ASRangeHandler.h */, + DE6D9E301C0AD9ED001A1DD3 /* ASRangeHandlerVisible.h */, + DE6D9E311C0AD9ED001A1DD3 /* ASRangeHandlerVisible.mm */, 292C599A1A956527007E5DD6 /* ASRangeHandlerPreload.h */, 292C599B1A956527007E5DD6 /* ASRangeHandlerPreload.mm */, 292C599D1A956527007E5DD6 /* ASRangeHandlerRender.h */, @@ -1159,6 +1167,7 @@ 05F20AA41A15733C00DCA68A /* ASImageProtocols.h in Headers */, 430E7C8F1B4C23F100697A4C /* ASIndexPath.h in Headers */, ACF6ED221B17843500DA7C62 /* ASInsetLayoutSpec.h in Headers */, + DE6D9E321C0AD9ED001A1DD3 /* ASRangeHandlerVisible.h in Headers */, ACF6ED4B1B17847A00DA7C62 /* ASInternalHelpers.h in Headers */, ACF6ED241B17843500DA7C62 /* ASLayout.h in Headers */, 251B8EFB1BBB3D690087C538 /* ASDataController+Subclasses.h in Headers */, @@ -1254,6 +1263,7 @@ B35062171B010EFD0018CF92 /* ASDataController.h in Headers */, B35062191B010EFD0018CF92 /* ASDealloc2MainObject.h in Headers */, 34EFC75B1B701BAF00AD841F /* ASDimension.h in Headers */, + DE6D9E331C0AD9ED001A1DD3 /* ASRangeHandlerVisible.h in Headers */, B350624F1B010EFD0018CF92 /* ASDisplayNode+DebugTiming.h in Headers */, B35061FD1B010EFD0018CF92 /* ASDisplayNode+Subclasses.h in Headers */, B35061FB1B010EFD0018CF92 /* ASDisplayNode.h in Headers */, @@ -1373,7 +1383,6 @@ 058D09B9195D04C000B7D73C /* Frameworks */, 058D09BA195D04C000B7D73C /* Resources */, 3B9D88CDF51B429C8409E4B6 /* Copy Pods Resources */, - 6CC5F540055A48FCA8C12BF5 /* Embed Pods Frameworks */, ); buildRules = ( ); @@ -1503,21 +1512,6 @@ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-AsyncDisplayKitTests/Pods-AsyncDisplayKitTests-resources.sh\"\n"; showEnvVarsInLog = 0; }; - 6CC5F540055A48FCA8C12BF5 /* 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; - }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -1599,6 +1593,7 @@ 055F1A3519ABD3E3004DAFF1 /* ASTableView.mm in Sources */, 058D0A17195D050800B7D73C /* ASTextNode.mm in Sources */, 058D0A1C195D050800B7D73C /* ASTextNodeCoreTextAdditions.m in Sources */, + DE6D9E341C0AD9ED001A1DD3 /* ASRangeHandlerVisible.mm in Sources */, 058D0A1D195D050800B7D73C /* ASTextNodeRenderer.mm in Sources */, 058D0A1E195D050800B7D73C /* ASTextNodeShadower.m in Sources */, 058D0A1F195D050800B7D73C /* ASTextNodeTextKitHelpers.mm in Sources */, @@ -1717,6 +1712,7 @@ 34EFC7741B701D0A00AD841F /* ASStaticLayoutSpec.mm in Sources */, B350620B1B010EFD0018CF92 /* ASTableView.mm in Sources */, B350620E1B010EFD0018CF92 /* ASTextNode.mm in Sources */, + DE6D9E351C0AD9ED001A1DD3 /* ASRangeHandlerVisible.mm in Sources */, B350622F1B010EFD0018CF92 /* ASTextNodeCoreTextAdditions.m in Sources */, B35062311B010EFD0018CF92 /* ASTextNodeRenderer.mm in Sources */, B35062331B010EFD0018CF92 /* ASTextNodeShadower.m in Sources */, diff --git a/AsyncDisplayKit/ASDisplayNode.h b/AsyncDisplayKit/ASDisplayNode.h index 45d23e07b8..80ee51aa6f 100644 --- a/AsyncDisplayKit/ASDisplayNode.h +++ b/AsyncDisplayKit/ASDisplayNode.h @@ -144,7 +144,6 @@ typedef NS_OPTIONS(NSUInteger, ASInterfaceState) /** @name Getting view and layer */ - /** * @abstract Returns a view. * @@ -181,14 +180,17 @@ typedef NS_OPTIONS(NSUInteger, ASInterfaceState) */ @property (nonatomic, readonly, retain) CALayer *layer; +/** + * @abstract Returns the Interface State 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; -- (void)enterInterfaceState:(ASInterfaceState)interfaceState; -- (void)exitInterfaceState:(ASInterfaceState)interfaceState; - /** @name Managing dimensions */ - /** * @abstract Asks the node to measure and return the size that best fits its subnodes. * diff --git a/AsyncDisplayKit/ASDisplayNode.mm b/AsyncDisplayKit/ASDisplayNode.mm index 8c639de1ba..298e683954 100644 --- a/AsyncDisplayKit/ASDisplayNode.mm +++ b/AsyncDisplayKit/ASDisplayNode.mm @@ -1650,6 +1650,7 @@ void recursivelyEnsureDisplayForLayer(CALayer *layer) _placeholderImage = nil; } +// TODO: Replace this with ASDisplayNodePerformBlockOnEveryNode or exitInterfaceState: - (void)recursivelyClearContents { for (ASDisplayNode *subnode in self.subnodes) { @@ -1663,6 +1664,7 @@ void recursivelyEnsureDisplayForLayer(CALayer *layer) // subclass override } +// TODO: Replace this with ASDisplayNodePerformBlockOnEveryNode or enterInterfaceState: - (void)recursivelyFetchData { for (ASDisplayNode *subnode in self.subnodes) { @@ -1676,6 +1678,7 @@ void recursivelyEnsureDisplayForLayer(CALayer *layer) // subclass override } +// TODO: Replace this with ASDisplayNodePerformBlockOnEveryNode or exitInterfaceState: - (void)recursivelyClearFetchedData { for (ASDisplayNode *subnode in self.subnodes) { @@ -1731,44 +1734,18 @@ void recursivelyEnsureDisplayForLayer(CALayer *layer) - (void)enterInterfaceState:(ASInterfaceState)interfaceState { - recursivelyPerformBlockOnEveryNode(nil, self, ^(ASDisplayNode *node) { + ASDisplayNodePerformBlockOnEveryNode(nil, self, ^(ASDisplayNode *node) { node.interfaceState |= interfaceState; }); } - (void)exitInterfaceState:(ASInterfaceState)interfaceState { - recursivelyPerformBlockOnEveryNode(nil, self, ^(ASDisplayNode *node) { - node.interfaceState &= (!interfaceState); + ASDisplayNodePerformBlockOnEveryNode(nil, self, ^(ASDisplayNode *node) { + node.interfaceState &= (~interfaceState); }); } -void recursivelyPerformBlockOnEveryNode(CALayer *layer, ASDisplayNode *node, void(^performOnNode)(ASDisplayNode *node)) -{ - if (!node) { - ASDisplayNodeCAssertNotNil(layer, @"Cannot recursively perform with nil node and nil layer"); - ASDisplayNodeCAssertMainThread(); - node = [layer asyncdisplaykit_node]; - } - - if (node) { - performOnNode(node); - } - if (!layer && [node isNodeLoaded]) { - layer = node.layer; - } - - if (layer) { - for (CALayer *sublayer in [layer sublayers]) { - recursivelyPerformBlockOnEveryNode(sublayer, nil, performOnNode); - } - } else if (node) { - for (ASDisplayNode *subnode in [node subnodes]) { - recursivelyPerformBlockOnEveryNode(nil, subnode, performOnNode); - } - } -} - - (void)layout { ASDisplayNodeAssertMainThread(); @@ -1825,6 +1802,7 @@ void recursivelyPerformBlockOnEveryNode(CALayer *layer, ASDisplayNode *node, voi - (void)setNeedsDisplayAtScale:(CGFloat)contentsScale { + ASDN::MutexLocker l(_propertyLock); if (contentsScale != self.contentsScaleForDisplay) { self.contentsScaleForDisplay = contentsScale; [self setNeedsDisplay]; @@ -1833,12 +1811,9 @@ void recursivelyPerformBlockOnEveryNode(CALayer *layer, ASDisplayNode *node, voi - (void)recursivelySetNeedsDisplayAtScale:(CGFloat)contentsScale { - [self setNeedsDisplayAtScale:contentsScale]; - - ASDN::MutexLocker l(_propertyLock); - for (ASDisplayNode *child in _subnodes) { - [child recursivelySetNeedsDisplayAtScale:contentsScale]; - } + ASDisplayNodePerformBlockOnEveryNode(nil, self, ^(ASDisplayNode *node) { + [node setNeedsDisplayAtScale:contentsScale]; + }); } - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event @@ -1974,6 +1949,7 @@ void recursivelyPerformBlockOnEveryNode(CALayer *layer, ASDisplayNode *node, voi _recursivelySetDisplaySuspended(self, nil, flag); } +// TODO: Replace this with ASDisplayNodePerformBlockOnEveryNode or a variant with a condition / test block. static void _recursivelySetDisplaySuspended(ASDisplayNode *node, CALayer *layer, BOOL flag) { // If there is no layer, but node whose its view is loaded, then we can traverse down its layer hierarchy. Otherwise we must stick to the node hierarchy to avoid loading views prematurely. Note that for nodes that haven't loaded their views, they can't possibly have subviews/sublayers, so we don't need to traverse the layer hierarchy for them. diff --git a/AsyncDisplayKit/ASDisplayNodeExtras.h b/AsyncDisplayKit/ASDisplayNodeExtras.h index 5ce6ac2ba5..ca12de19a8 100644 --- a/AsyncDisplayKit/ASDisplayNodeExtras.h +++ b/AsyncDisplayKit/ASDisplayNodeExtras.h @@ -24,6 +24,14 @@ extern ASDisplayNode *ASLayerToDisplayNode(CALayer *layer); */ extern ASDisplayNode *ASViewToDisplayNode(UIView *view); +/** + This function will walk the layer heirarchy, spanning discontinuous sections of the node heirarchy (e.g. the layers + of UIKit intermediate views in UIViewControllers, UITableView, UICollectionView). + In the event that a node's backing layer is not created yet, the function will only walk the direct subnodes instead + of forcing the layer heirarchy to be created. + */ +void ASDisplayNodePerformBlockOnEveryNode(CALayer *layer, ASDisplayNode *node, void(^block)(ASDisplayNode *node)); + /** Given a display node, traverses up the layer tree hierarchy, returning the first display node that passes block. */ diff --git a/AsyncDisplayKit/ASDisplayNodeExtras.mm b/AsyncDisplayKit/ASDisplayNodeExtras.mm index 8d2e261570..721e536785 100644 --- a/AsyncDisplayKit/ASDisplayNodeExtras.mm +++ b/AsyncDisplayKit/ASDisplayNodeExtras.mm @@ -10,16 +10,42 @@ #import "ASDisplayNodeInternal.h" -ASDisplayNode *ASLayerToDisplayNode(CALayer *layer) +inline ASDisplayNode *ASLayerToDisplayNode(CALayer *layer) { return layer.asyncdisplaykit_node; } -ASDisplayNode *ASViewToDisplayNode(UIView *view) +inline ASDisplayNode *ASViewToDisplayNode(UIView *view) { return view.asyncdisplaykit_node; } +void ASDisplayNodePerformBlockOnEveryNode(CALayer *layer, ASDisplayNode *node, void(^block)(ASDisplayNode *node)) +{ + if (!node) { + ASDisplayNodeCAssertNotNil(layer, @"Cannot recursively perform with nil node and nil layer"); + ASDisplayNodeCAssertMainThread(); + node = ASLayerToDisplayNode(layer); + } + + if (node) { + block(node); + } + if (!layer && [node isNodeLoaded]) { + layer = node.layer; + } + + if (layer) { + for (CALayer *sublayer in [layer sublayers]) { + ASDisplayNodePerformBlockOnEveryNode(sublayer, nil, block); + } + } else if (node) { + for (ASDisplayNode *subnode in [node subnodes]) { + ASDisplayNodePerformBlockOnEveryNode(nil, subnode, block); + } + } +} + id ASDisplayNodeFind(ASDisplayNode *node, BOOL (^block)(ASDisplayNode *node)) { CALayer *layer = node.layer; diff --git a/AsyncDisplayKit/Details/ASAbstractLayoutController.mm b/AsyncDisplayKit/Details/ASAbstractLayoutController.mm index 30723e43b7..1aef1c1e0e 100644 --- a/AsyncDisplayKit/Details/ASAbstractLayoutController.mm +++ b/AsyncDisplayKit/Details/ASAbstractLayoutController.mm @@ -26,14 +26,19 @@ } _tuningParameters = std::vector(ASLayoutRangeTypeCount); + _tuningParameters[ASLayoutRangeTypeVisible] = { + .leadingBufferScreenfuls = 0, + .trailingBufferScreenfuls = 0 + }; + _tuningParameters[ASLayoutRangeTypeRender] = { + .leadingBufferScreenfuls = 1.5, + .trailingBufferScreenfuls = 0.75 + }; _tuningParameters[ASLayoutRangeTypePreload] = { .leadingBufferScreenfuls = 3, .trailingBufferScreenfuls = 2 }; - _tuningParameters[ASLayoutRangeTypeRender] = { - .leadingBufferScreenfuls = 2, - .trailingBufferScreenfuls = 1 - }; + return self; } @@ -49,6 +54,7 @@ - (void)setTuningParameters:(ASRangeTuningParameters)tuningParameters forRangeType:(ASLayoutRangeType)rangeType { ASDisplayNodeAssert(rangeType < _tuningParameters.size(), @"Requesting a range that is OOB for the configured tuning parameters"); + ASDisplayNodeAssert(rangeType != ASLayoutRangeTypeVisible, @"Must not set Visible range tuning parameters (always 0, 0)"); _tuningParameters[rangeType] = tuningParameters; } diff --git a/AsyncDisplayKit/Details/ASLayoutRangeType.h b/AsyncDisplayKit/Details/ASLayoutRangeType.h index 128b88b9fe..a5f2075485 100644 --- a/AsyncDisplayKit/Details/ASLayoutRangeType.h +++ b/AsyncDisplayKit/Details/ASLayoutRangeType.h @@ -9,6 +9,7 @@ #import typedef NS_ENUM(NSInteger, ASLayoutRangeType) { + ASLayoutRangeTypeVisible, ASLayoutRangeTypeRender, ASLayoutRangeTypePreload, ASLayoutRangeTypeCount diff --git a/AsyncDisplayKit/Details/ASRangeController.mm b/AsyncDisplayKit/Details/ASRangeController.mm index 1907baff75..ccbeff0c66 100644 --- a/AsyncDisplayKit/Details/ASRangeController.mm +++ b/AsyncDisplayKit/Details/ASRangeController.mm @@ -11,6 +11,7 @@ #import "ASAssert.h" #import "ASDisplayNodeExtras.h" #import "ASMultiDimensionalArrayUtils.h" +#import "ASRangeHandlerVisible.h" #import "ASRangeHandlerRender.h" #import "ASRangeHandlerPreload.h" #import "ASInternalHelpers.h" @@ -36,6 +37,7 @@ _rangeIsValid = YES; _rangeTypeIndexPaths = [NSMutableDictionary dictionary]; _rangeTypeHandlers = @{ + @(ASLayoutRangeTypeVisible): [[ASRangeHandlerVisible alloc] init], @(ASLayoutRangeTypeRender): [[ASRangeHandlerRender alloc] init], @(ASLayoutRangeTypePreload): [[ASRangeHandlerPreload alloc] init], }; diff --git a/AsyncDisplayKit/Details/ASRangeHandlerPreload.mm b/AsyncDisplayKit/Details/ASRangeHandlerPreload.mm index fc61788fb0..adbbf5ecfb 100644 --- a/AsyncDisplayKit/Details/ASRangeHandlerPreload.mm +++ b/AsyncDisplayKit/Details/ASRangeHandlerPreload.mm @@ -7,9 +7,8 @@ */ #import "ASRangeHandlerPreload.h" - #import "ASDisplayNode.h" -#import "ASDisplayNode+Subclasses.h" +#import "ASDisplayNodeInternal.h" @implementation ASRangeHandlerPreload diff --git a/AsyncDisplayKit/Details/ASRangeHandlerVisible.h b/AsyncDisplayKit/Details/ASRangeHandlerVisible.h new file mode 100644 index 0000000000..eab9f77f29 --- /dev/null +++ b/AsyncDisplayKit/Details/ASRangeHandlerVisible.h @@ -0,0 +1,15 @@ +/* Copyright (c) 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import + +#import + +@interface ASRangeHandlerVisible : NSObject + +@end diff --git a/AsyncDisplayKit/Details/ASRangeHandlerVisible.mm b/AsyncDisplayKit/Details/ASRangeHandlerVisible.mm new file mode 100644 index 0000000000..d8daf51889 --- /dev/null +++ b/AsyncDisplayKit/Details/ASRangeHandlerVisible.mm @@ -0,0 +1,25 @@ +/* Copyright (c) 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "ASRangeHandlerVisible.h" +#import "ASDisplayNode.h" +#import "ASDisplayNodeInternal.h" + +@implementation ASRangeHandlerVisible + +- (void)node:(ASDisplayNode *)node enteredRangeOfType:(ASLayoutRangeType)rangeType +{ + [node enterInterfaceState:ASInterfaceStateVisible]; +} + +- (void)node:(ASDisplayNode *)node exitedRangeOfType:(ASLayoutRangeType)rangeType +{ + [node exitInterfaceState:ASInterfaceStateVisible]; +} + +@end diff --git a/AsyncDisplayKit/Private/ASDisplayNodeInternal.h b/AsyncDisplayKit/Private/ASDisplayNodeInternal.h index 4953a5b538..156e6f7730 100644 --- a/AsyncDisplayKit/Private/ASDisplayNodeInternal.h +++ b/AsyncDisplayKit/Private/ASDisplayNodeInternal.h @@ -118,6 +118,10 @@ typedef NS_OPTIONS(NSUInteger, ASDisplayNodeMethodOverrides) { // Bitmask to check which methods an object overrides. @property (nonatomic, assign, readonly) ASDisplayNodeMethodOverrides methodOverrides; +// These methods are recursive, and either union or remove the provided interfaceState to all sub-elements. +- (void)enterInterfaceState:(ASInterfaceState)interfaceState; +- (void)exitInterfaceState:(ASInterfaceState)interfaceState; + // Swizzle to extend the builtin functionality with custom logic - (BOOL)__shouldLoadViewOrLayer; - (BOOL)__shouldSize;