diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index 4e8a7a19af..fa52798d74 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -115,6 +115,7 @@ 68355B3E1CB57A60001D4E68 /* ASPINRemoteImageDownloader.m in Sources */ = {isa = PBXBuildFile; fileRef = 68355B361CB57A5A001D4E68 /* ASPINRemoteImageDownloader.m */; }; 68355B401CB57A69001D4E68 /* ASImageContainerProtocolCategories.m in Sources */ = {isa = PBXBuildFile; fileRef = 68355B381CB57A5A001D4E68 /* ASImageContainerProtocolCategories.m */; }; 68355B411CB57A6C001D4E68 /* ASImageContainerProtocolCategories.h in Headers */ = {isa = PBXBuildFile; fileRef = 68355B371CB57A5A001D4E68 /* ASImageContainerProtocolCategories.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 683F563720E409D700CEB7A3 /* ASDisplayNode+InterfaceState.h in Headers */ = {isa = PBXBuildFile; fileRef = 683F563620E409D600CEB7A3 /* ASDisplayNode+InterfaceState.h */; settings = {ATTRIBUTES = (Public, ); }; }; 68AF37DB1CBEF4D80077BF76 /* ASImageNode+AnimatedImagePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 68B8A4DB1CBD911D007E4543 /* ASImageNode+AnimatedImagePrivate.h */; settings = {ATTRIBUTES = (Private, ); }; }; 68B0277B1C1A79D60041016B /* ASDisplayNode+Beta.h in Headers */ = {isa = PBXBuildFile; fileRef = 68B027791C1A79CC0041016B /* ASDisplayNode+Beta.h */; settings = {ATTRIBUTES = (Public, ); }; }; 68B8A4E21CBDB958007E4543 /* ASWeakProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 68B8A4DF1CBDB958007E4543 /* ASWeakProxy.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -667,6 +668,7 @@ 68355B371CB57A5A001D4E68 /* ASImageContainerProtocolCategories.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASImageContainerProtocolCategories.h; sourceTree = ""; }; 68355B381CB57A5A001D4E68 /* ASImageContainerProtocolCategories.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASImageContainerProtocolCategories.m; sourceTree = ""; }; 68355B391CB57A5A001D4E68 /* ASPINRemoteImageDownloader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASPINRemoteImageDownloader.h; sourceTree = ""; }; + 683F563620E409D600CEB7A3 /* ASDisplayNode+InterfaceState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ASDisplayNode+InterfaceState.h"; sourceTree = ""; }; 68B027791C1A79CC0041016B /* ASDisplayNode+Beta.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ASDisplayNode+Beta.h"; sourceTree = ""; }; 68B8A4DB1CBD911D007E4543 /* ASImageNode+AnimatedImagePrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ASImageNode+AnimatedImagePrivate.h"; sourceTree = ""; }; 68B8A4DF1CBDB958007E4543 /* ASWeakProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASWeakProxy.h; sourceTree = ""; }; @@ -1156,6 +1158,7 @@ 68B027791C1A79CC0041016B /* ASDisplayNode+Beta.h */, CC034A071E60BEB400626263 /* ASDisplayNode+Convenience.h */, CC034A081E60BEB400626263 /* ASDisplayNode+Convenience.m */, + 683F563620E409D600CEB7A3 /* ASDisplayNode+InterfaceState.h */, 69BCE3D71EC6513B007DCCAD /* ASDisplayNode+Layout.mm */, 058D09DA195D050800B7D73C /* ASDisplayNode+Subclasses.h */, 90FC784E1E4BFE1B00383C5A /* ASDisplayNode+Yoga.mm */, @@ -1915,6 +1918,7 @@ CC034A091E60BEB400626263 /* ASDisplayNode+Convenience.h in Headers */, 254C6B7E1BF94DF4003EC431 /* ASTextKitTailTruncater.h in Headers */, B35062491B010EFD0018CF92 /* _ASCoreAnimationExtras.h in Headers */, + 683F563720E409D700CEB7A3 /* ASDisplayNode+InterfaceState.h in Headers */, 68EE0DBE1C1B4ED300BA1B99 /* ASMainSerialQueue.h in Headers */, CCCCCCE11EC3EF060087FE10 /* ASTextUtilities.h in Headers */, B350624B1B010EFD0018CF92 /* _ASPendingState.h in Headers */, diff --git a/CHANGELOG.md b/CHANGELOG.md index e74bac89d6..605ac24a01 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ## master * Add your own contributions to the next release on the line below this with your name. +- [ASDisplayNode] Adds support for multiple interface state delegates. [Garrett Moon](https://github.com/garrettmoon) [#979](https://github.com/TextureGroup/Texture/pull/979) - [ASDataController] Add capability to renew supplementary views (update map) when size change from zero to non-zero.[Max Wang](https://github.com/wsdwsd0829) [#842](https://github.com/TextureGroup/Texture/pull/842) - Make `ASPerformMainThreadDeallocation` visible in C. [Adlai Holler](https://github.com/Adlai-Holler) - Add snapshot test for astextnode2. [Max Wang](https://github.com/wsdwsd0829) [#935](https://github.com/TextureGroup/Texture/pull/935) diff --git a/Source/ASDisplayNode+InterfaceState.h b/Source/ASDisplayNode+InterfaceState.h new file mode 100644 index 0000000000..bff9fa9ef9 --- /dev/null +++ b/Source/ASDisplayNode+InterfaceState.h @@ -0,0 +1,124 @@ +// +// ASDisplayNode+InterfaceState.h +// Texture +// +// Copyright (c) 2017-present, Pinterest, Inc. All rights reserved. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// + +#import + +/** + * Interface state is available on ASDisplayNode and ASViewController, and + * allows checking whether a node is in an interface situation where it is prudent to trigger certain + * actions: measurement, data loading, display, and visibility (the latter for animations or other onscreen-only effects). + * + * The defualt state, ASInterfaceStateNone, means that the element is not predicted to be onscreen soon and + * preloading should not be performed. Swift: use [] for the default behavior. + */ +typedef NS_OPTIONS(NSUInteger, ASInterfaceState) +{ + /** The element is not predicted to be onscreen soon and preloading should not be performed */ + ASInterfaceStateNone = 0, + /** The element may be added to a view soon that could become visible. Measure the layout, including size calculation. */ + ASInterfaceStateMeasureLayout = 1 << 0, + /** The element is likely enough to come onscreen that disk and/or network data required for display should be fetched. */ + ASInterfaceStatePreload = 1 << 1, + /** The element is very likely to become visible, and concurrent rendering should be executed for any -setNeedsDisplay. */ + ASInterfaceStateDisplay = 1 << 2, + /** The element is physically onscreen by at least 1 pixel. + In practice, all other bit fields should also be set when this flag is set. */ + ASInterfaceStateVisible = 1 << 3, + + /** + * The node is not contained in a cell but it is in a window. + * + * Currently we only set `interfaceState` to other values for + * nodes contained in table views or collection views. + */ + ASInterfaceStateInHierarchy = ASInterfaceStateMeasureLayout | ASInterfaceStatePreload | ASInterfaceStateDisplay | ASInterfaceStateVisible, +}; + +@protocol ASInterfaceStateDelegate +@optional + +/** + * @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; + +/** + * @abstract Called whenever the node becomes visible. + * @discussion Subclasses may use this to monitor when they become visible. + * @note This method is guaranteed to be called on main. + */ +- (void)didEnterVisibleState; + +/** + * @abstract Called whenever the node is no longer visible. + * @discussion Subclasses may use this to monitor when they are no longer visible. + * @note This method is guaranteed to be called on main. + */ +- (void)didExitVisibleState; + +/** + * @abstract Called whenever the the node has entered the display state. + * @discussion Subclasses may use this to monitor when a node should be rendering its content. + * @note This method is guaranteed to be called on main. + */ +- (void)didEnterDisplayState; + +/** + * @abstract Called whenever the the node has exited the display state. + * @discussion Subclasses may use this to monitor when a node should no longer be rendering its content. + * @note This method is guaranteed to be called on main. + */ +- (void)didExitDisplayState; + +/** + * @abstract Called whenever the the node has entered the preload state. + * @discussion Subclasses may use this to monitor data for a node should be preloaded, either from a local or remote source. + * @note This method is guaranteed to be called on main. + */ +- (void)didEnterPreloadState; + +/** + * @abstract Called whenever the the node has exited the preload state. + * @discussion Subclasses may use this to monitor whether preloading data for a node should be canceled. + * @note This method is guaranteed to be called on main. + */ +- (void)didExitPreloadState; + +/** + * @abstract Called when the node has completed applying the layout. + * @discussion Can be used for operations that are performed after layout has completed. + * @note This method is guaranteed to be called on main. + */ +- (void)nodeDidLayout; + +/** + * @abstract Called when the node loads. + * @discussion Can be used for operations that are performed after the node's view is available. + * @note This method is guaranteed to be called on main. + */ +- (void)nodeDidLoad; + +/** + * @abstract Indicates that the receiver and all subnodes have finished displaying. + * @discussion May be called more than once, for example if the receiver has a network image node. + * This is called after the first display pass even if network image nodes have not downloaded anything + * (text would be done, and other nodes that are ready to do their final display). Each render of + * every progressive jpeg network node would cause this to be called, so this hook could be called up to + * 1 + (pJPEGcount * pJPEGrenderCount) times. The render count depends on how many times the downloader calls + * the progressImage block. + * @note This method is guaranteed to be called on main. + */ +- (void)hierarchyDisplayDidFinish; + +@end diff --git a/Source/ASDisplayNode+Subclasses.h b/Source/ASDisplayNode+Subclasses.h index 43f1c235f0..d4cbc39f2d 100644 --- a/Source/ASDisplayNode+Subclasses.h +++ b/Source/ASDisplayNode+Subclasses.h @@ -42,74 +42,6 @@ NS_ASSUME_NONNULL_BEGIN * variables. */ -@protocol ASInterfaceStateDelegate -@required - -/** - * @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; - -/** - * @abstract Called whenever the node becomes visible. - * @discussion Subclasses may use this to monitor when they become visible. - * @note This method is guaranteed to be called on main. - */ -- (void)didEnterVisibleState; - -/** - * @abstract Called whenever the node is no longer visible. - * @discussion Subclasses may use this to monitor when they are no longer visible. - * @note This method is guaranteed to be called on main. - */ -- (void)didExitVisibleState; - -/** - * @abstract Called whenever the the node has entered the display state. - * @discussion Subclasses may use this to monitor when a node should be rendering its content. - * @note This method is guaranteed to be called on main. - */ -- (void)didEnterDisplayState; - -/** - * @abstract Called whenever the the node has exited the display state. - * @discussion Subclasses may use this to monitor when a node should no longer be rendering its content. - * @note This method is guaranteed to be called on main. - */ -- (void)didExitDisplayState; - -/** - * @abstract Called whenever the the node has entered the preload state. - * @discussion Subclasses may use this to monitor data for a node should be preloaded, either from a local or remote source. - * @note This method is guaranteed to be called on main. - */ -- (void)didEnterPreloadState; - -/** - * @abstract Called whenever the the node has exited the preload state. - * @discussion Subclasses may use this to monitor whether preloading data for a node should be canceled. - * @note This method is guaranteed to be called on main. - */ -- (void)didExitPreloadState; - -/** - * @abstract Called when the node has completed applying the layout. - * @discussion Can be used for operations that are performed after layout has completed. - * @note This method is guaranteed to be called on main. - */ -- (void)nodeDidLayout; - -/** - * @abstract Called when the node loads. - * @discussion Can be used for operations that are performed after the node's view is available. - * @note This method is guaranteed to be called on main. - */ -- (void)nodeDidLoad; - -@end - @interface ASDisplayNode (Subclassing) #pragma mark - Properties diff --git a/Source/ASDisplayNode.h b/Source/ASDisplayNode.h index e8dcb03c91..dbe641e9b5 100644 --- a/Source/ASDisplayNode.h +++ b/Source/ASDisplayNode.h @@ -22,6 +22,7 @@ #import #import #import +#import #import #import #import @@ -70,37 +71,6 @@ typedef ASLayoutSpec * _Nonnull(^ASLayoutSpecBlock)(__kindof ASDisplayNode *node */ typedef void (^ASDisplayNodeNonFatalErrorBlock)(NSError *error); -/** - * Interface state is available on ASDisplayNode and ASViewController, and - * allows checking whether a node is in an interface situation where it is prudent to trigger certain - * actions: measurement, data loading, display, and visibility (the latter for animations or other onscreen-only effects). - * - * The defualt state, ASInterfaceStateNone, means that the element is not predicted to be onscreen soon and - * preloading should not be performed. Swift: use [] for the default behavior. - */ -typedef NS_OPTIONS(NSUInteger, ASInterfaceState) -{ - /** The element is not predicted to be onscreen soon and preloading should not be performed */ - ASInterfaceStateNone = 0, - /** The element may be added to a view soon that could become visible. Measure the layout, including size calculation. */ - ASInterfaceStateMeasureLayout = 1 << 0, - /** The element is likely enough to come onscreen that disk and/or network data required for display should be fetched. */ - ASInterfaceStatePreload = 1 << 1, - /** The element is very likely to become visible, and concurrent rendering should be executed for any -setNeedsDisplay. */ - ASInterfaceStateDisplay = 1 << 2, - /** The element is physically onscreen by at least 1 pixel. - In practice, all other bit fields should also be set when this flag is set. */ - ASInterfaceStateVisible = 1 << 3, - - /** - * The node is not contained in a cell but it is in a window. - * - * Currently we only set `interfaceState` to other values for - * nodes contained in table views or collection views. - */ - ASInterfaceStateInHierarchy = ASInterfaceStateMeasureLayout | ASInterfaceStatePreload | ASInterfaceStateDisplay | ASInterfaceStateVisible, -}; - typedef NS_ENUM(NSInteger, ASCornerRoundingType) { ASCornerRoundingTypeDefaultSlowCALayer, ASCornerRoundingTypePrecomposited, @@ -292,6 +262,24 @@ AS_EXTERN NSInteger const ASDefaultDrawingPriority; */ @property (readonly) ASInterfaceState interfaceState; +/** + * @abstract Adds a delegate to receive notifications on interfaceState changes. + * + * @warning This must be called from the main thread. + * + * @see ASInterfaceState + */ +- (void)addInterfaceStateDelegate:(id )interfaceStateDelegate; + +/** + * @abstract Removes a delegate from receiving notifications on interfaceState changes. + * + * @warning This must be called from the main thread. + * + * @see ASInterfaceState + */ +- (void)removeInterfaceStateDelegate:(id )interfaceStateDelegate; + /** * @abstract Class property that allows to set a block that can be called on non-fatal errors. This * property can be useful for cases when Async Display Kit can recover from an abnormal behavior, but diff --git a/Source/ASDisplayNode.mm b/Source/ASDisplayNode.mm index e705522841..81ab1cd618 100644 --- a/Source/ASDisplayNode.mm +++ b/Source/ASDisplayNode.mm @@ -36,6 +36,7 @@ #import #import #import +#import #import #import #import @@ -71,7 +72,6 @@ NSInteger const ASDefaultDrawingPriority = ASDefaultTransactionPriority; @protocol CALayerDelegate; @interface ASDisplayNode () - /** * See ASDisplayNodeInternal.h for ivars */ @@ -544,7 +544,11 @@ ASSynthesizeLockingMethodsWithMutex(__instanceLock__); block(self); } - [_interfaceStateDelegate nodeDidLoad]; + for (id delegate in _interfaceStateDelegates) { + if ([delegate respondsToSelector:@selector(nodeDidLoad)]) { + [delegate nodeDidLoad]; + } + } } - (void)didLoad @@ -1225,7 +1229,11 @@ ASSynthesizeLockingMethodsWithMutex(__instanceLock__); ASDisplayNodeAssertMainThread(); ASDisplayNodeAssertLockUnownedByCurrentThread(__instanceLock__); ASDisplayNodeAssertTrue(self.isNodeLoaded); - [_interfaceStateDelegate nodeDidLayout]; + for (id delegate in _interfaceStateDelegates) { + if ([delegate respondsToSelector:@selector(nodeDidLayout)]) { + [delegate nodeDidLayout]; + } + } } #pragma mark Layout Transition @@ -1447,6 +1455,13 @@ NSString * const ASRenderingEngineDidDisplayNodesScheduledBeforeTimestamp = @"AS if (_pendingDisplayNodes.isEmpty) { [self hierarchyDisplayDidFinish]; + + for (id delegate in _interfaceStateDelegates) { + if ([delegate respondsToSelector:@selector(hierarchyDisplayDidFinish)]) { + [delegate hierarchyDisplayDidFinish]; + } + } + BOOL placeholderShouldPersist = [self placeholderShouldPersist]; __instanceLock__.lock(); @@ -3142,7 +3157,12 @@ ASDISPLAYNODE_INLINE BOOL subtreeIsRasterized(ASDisplayNode *node) { { // Subclass hook ASDisplayNodeAssertLockUnownedByCurrentThread(__instanceLock__); - [_interfaceStateDelegate interfaceStateDidChange:newState fromState:oldState]; + ASDisplayNodeAssertMainThread(); + for (id delegate in _interfaceStateDelegates) { + if ([delegate respondsToSelector:@selector(interfaceStateDidChange:fromState:)]) { + [delegate interfaceStateDidChange:newState fromState:oldState]; + } + } } - (BOOL)shouldScheduleDisplayWithNewInterfaceState:(ASInterfaceState)newInterfaceState @@ -3152,6 +3172,24 @@ ASDISPLAYNODE_INLINE BOOL subtreeIsRasterized(ASDisplayNode *node) { return willDisplay && (willDisplay != nowDisplay); } +- (void)addInterfaceStateDelegate:(id )interfaceStateDelegate +{ + ASDisplayNodeAssertMainThread(); + + // Not a fan of lazy loading, but this method won't get called very often and avoiding + // the overhead of creating this is probably worth it. + if (_interfaceStateDelegates == nil) { + _interfaceStateDelegates = [NSHashTable weakObjectsHashTable]; + } + [_interfaceStateDelegates addObject:interfaceStateDelegate]; +} + +- (void)removeInterfaceStateDelegate:(id )interfaceStateDelegate +{ + ASDisplayNodeAssertMainThread(); + [_interfaceStateDelegates removeObject:interfaceStateDelegate]; +} + - (BOOL)isVisible { ASDN::MutexLocker l(__instanceLock__); @@ -3163,7 +3201,11 @@ ASDISPLAYNODE_INLINE BOOL subtreeIsRasterized(ASDisplayNode *node) { // subclass override ASDisplayNodeAssertMainThread(); ASDisplayNodeAssertLockUnownedByCurrentThread(__instanceLock__); - [_interfaceStateDelegate didEnterVisibleState]; + for (id delegate in _interfaceStateDelegates) { + if ([delegate respondsToSelector:@selector(didEnterVisibleState)]) { + [delegate didEnterVisibleState]; + } + } #if AS_ENABLE_TIPS [ASTipsController.shared nodeDidAppear:self]; #endif @@ -3174,7 +3216,11 @@ ASDISPLAYNODE_INLINE BOOL subtreeIsRasterized(ASDisplayNode *node) { // subclass override ASDisplayNodeAssertMainThread(); ASDisplayNodeAssertLockUnownedByCurrentThread(__instanceLock__); - [_interfaceStateDelegate didExitVisibleState]; + for (id delegate in _interfaceStateDelegates) { + if ([delegate respondsToSelector:@selector(didExitVisibleState)]) { + [delegate didExitVisibleState]; + } + } } - (BOOL)isInDisplayState @@ -3188,7 +3234,11 @@ ASDISPLAYNODE_INLINE BOOL subtreeIsRasterized(ASDisplayNode *node) { // subclass override ASDisplayNodeAssertMainThread(); ASDisplayNodeAssertLockUnownedByCurrentThread(__instanceLock__); - [_interfaceStateDelegate didEnterDisplayState]; + for (id delegate in _interfaceStateDelegates) { + if ([delegate respondsToSelector:@selector(didEnterDisplayState)]) { + [delegate didEnterDisplayState]; + } + } } - (void)didExitDisplayState @@ -3196,7 +3246,11 @@ ASDISPLAYNODE_INLINE BOOL subtreeIsRasterized(ASDisplayNode *node) { // subclass override ASDisplayNodeAssertMainThread(); ASDisplayNodeAssertLockUnownedByCurrentThread(__instanceLock__); - [_interfaceStateDelegate didExitDisplayState]; + for (id delegate in _interfaceStateDelegates) { + if ([delegate respondsToSelector:@selector(didExitDisplayState)]) { + [delegate didExitDisplayState]; + } + } } - (BOOL)isInPreloadState @@ -3247,14 +3301,22 @@ ASDISPLAYNODE_INLINE BOOL subtreeIsRasterized(ASDisplayNode *node) { [self layoutIfNeeded]; } - [_interfaceStateDelegate didEnterPreloadState]; + for (id delegate in _interfaceStateDelegates) { + if ([delegate respondsToSelector:@selector(didEnterPreloadState)]) { + [delegate didEnterPreloadState]; + } + } } - (void)didExitPreloadState { ASDisplayNodeAssertMainThread(); ASDisplayNodeAssertLockUnownedByCurrentThread(__instanceLock__); - [_interfaceStateDelegate didExitPreloadState]; + for (id delegate in _interfaceStateDelegates) { + if ([delegate respondsToSelector:@selector(didExitPreloadState)]) { + [delegate didExitPreloadState]; + } + } } - (void)clearContents diff --git a/Source/ASNodeController+Beta.m b/Source/ASNodeController+Beta.m index 1bd873e763..5f5fcddf66 100644 --- a/Source/ASNodeController+Beta.m +++ b/Source/ASNodeController+Beta.m @@ -15,9 +15,10 @@ // http://www.apache.org/licenses/LICENSE-2.0 // -#import -#import +#import #import +#import +#import #define _node (_shouldInvertStrongReference ? _weakNode : _strongNode) @@ -74,7 +75,7 @@ _weakNode = nil; } - node.interfaceStateDelegate = self; + [node addInterfaceStateDelegate:self]; } - (void)setNode:(ASDisplayNode *)node diff --git a/Source/Private/ASDisplayNode+FrameworkPrivate.h b/Source/Private/ASDisplayNode+FrameworkPrivate.h index 589d60c22c..245d9f382c 100644 --- a/Source/Private/ASDisplayNode+FrameworkPrivate.h +++ b/Source/Private/ASDisplayNode+FrameworkPrivate.h @@ -138,9 +138,6 @@ __unused static NSString * _Nonnull NSStringFromASHierarchyStateChange(ASHierarc // Returns the bounds of the node without reaching the view or layer - (CGRect)_locked_threadSafeBounds; -// delegate to inform of ASInterfaceState changes (used by ASNodeController) -@property (nonatomic, weak) id interfaceStateDelegate; - // The -pendingInterfaceState holds the value that will be applied to -interfaceState by the // ASCATransactionQueue. If already applied, it matches -interfaceState. Thread-safe access. @property (nonatomic, readonly) ASInterfaceState pendingInterfaceState; diff --git a/Source/Private/ASDisplayNodeInternal.h b/Source/Private/ASDisplayNodeInternal.h index 18c93f103d..9146a4f1e1 100644 --- a/Source/Private/ASDisplayNodeInternal.h +++ b/Source/Private/ASDisplayNodeInternal.h @@ -241,6 +241,8 @@ AS_EXTERN NSString * const ASRenderingEngineDidDisplayNodesScheduledBeforeTimest NSTimeInterval _debugTimeToAddSubnodeViews; NSTimeInterval _debugTimeForDidLoad; #endif + + NSHashTable > *_interfaceStateDelegates; } + (void)scheduleNodeForRecursiveDisplay:(ASDisplayNode *)node;