ASDisplayNode+FrameworkPrivate.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. //
  2. // ASDisplayNode+FrameworkPrivate.h
  3. // AsyncDisplayKit
  4. //
  5. // Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
  6. // This source code is licensed under the BSD-style license found in the
  7. // LICENSE file in the root directory of this source tree. An additional grant
  8. // of patent rights can be found in the PATENTS file in the same directory.
  9. //
  10. //
  11. // The following methods are ONLY for use by _ASDisplayLayer, _ASDisplayView, and ASDisplayNode.
  12. // These methods must never be called or overridden by other classes.
  13. //
  14. #import "ASDisplayNode.h"
  15. #import "ASThread.h"
  16. #import "ASObjectDescriptionHelpers.h"
  17. NS_ASSUME_NONNULL_BEGIN
  18. /**
  19. Hierarchy state is propagated from nodes to all of their children when certain behaviors are required from the subtree.
  20. Examples include rasterization and external driving of the .interfaceState property.
  21. By passing this information explicitly, performance is optimized by avoiding iteration up the supernode chain.
  22. Lastly, this avoidance of supernode traversal protects against the possibility of deadlocks when a supernode is
  23. simultaneously attempting to materialize views / layers for its subtree (as many related methods require property locking)
  24. Note: as the hierarchy deepens, more state properties may be enabled. However, state properties may never be disabled /
  25. cancelled below the point they are enabled. They continue to the leaves of the hierarchy.
  26. */
  27. typedef NS_OPTIONS(NSUInteger, ASHierarchyState)
  28. {
  29. /** The node may or may not have a supernode, but no supernode has a special hierarchy-influencing option enabled. */
  30. ASHierarchyStateNormal = 0,
  31. /** The node has a supernode with .shouldRasterizeDescendants = YES.
  32. Note: the root node of the rasterized subtree (the one with the property set on it) will NOT have this state set. */
  33. ASHierarchyStateRasterized = 1 << 0,
  34. /** The node or one of its supernodes is managed by a class like ASRangeController. Most commonly, these nodes are
  35. ASCellNode objects or a subnode of one, and are used in ASTableView or ASCollectionView.
  36. These nodes also receive regular updates to the .interfaceState property with more detailed status information. */
  37. ASHierarchyStateRangeManaged = 1 << 1,
  38. /** Down-propagated version of _flags.visibilityNotificationsDisabled. This flag is very rarely set, but by having it
  39. locally available to nodes, they do not have to walk up supernodes at the critical points it is checked. */
  40. ASHierarchyStateTransitioningSupernodes = 1 << 2,
  41. /** One of the supernodes of this node is performing a transition.
  42. Any layout calculated during this state should not be applied immediately, but pending until later. */
  43. ASHierarchyStateLayoutPending = 1 << 3,
  44. ASHierarchyStateVisualizeLayout = 1 << 4
  45. };
  46. ASDISPLAYNODE_INLINE BOOL ASHierarchyStateIncludesLayoutPending(ASHierarchyState hierarchyState)
  47. {
  48. return ((hierarchyState & ASHierarchyStateLayoutPending) == ASHierarchyStateLayoutPending);
  49. }
  50. ASDISPLAYNODE_INLINE BOOL ASHierarchyStateIncludesRangeManaged(ASHierarchyState hierarchyState)
  51. {
  52. return ((hierarchyState & ASHierarchyStateRangeManaged) == ASHierarchyStateRangeManaged);
  53. }
  54. ASDISPLAYNODE_INLINE BOOL ASHierarchyStateIncludesVisualizeLayout(ASHierarchyState hierarchyState)
  55. {
  56. return ((hierarchyState & ASHierarchyStateVisualizeLayout) == ASHierarchyStateVisualizeLayout);
  57. }
  58. ASDISPLAYNODE_INLINE BOOL ASHierarchyStateIncludesRasterized(ASHierarchyState hierarchyState)
  59. {
  60. return ((hierarchyState & ASHierarchyStateRasterized) == ASHierarchyStateRasterized);
  61. }
  62. ASDISPLAYNODE_INLINE BOOL ASHierarchyStateIncludesTransitioningSupernodes(ASHierarchyState hierarchyState)
  63. {
  64. return ((hierarchyState & ASHierarchyStateTransitioningSupernodes) == ASHierarchyStateTransitioningSupernodes);
  65. }
  66. __unused static NSString * _Nonnull NSStringFromASHierarchyState(ASHierarchyState hierarchyState)
  67. {
  68. NSMutableArray *states = [NSMutableArray array];
  69. if (hierarchyState == ASHierarchyStateNormal) {
  70. [states addObject:@"Normal"];
  71. }
  72. if (ASHierarchyStateIncludesRangeManaged(hierarchyState)) {
  73. [states addObject:@"RangeManaged"];
  74. }
  75. if (ASHierarchyStateIncludesLayoutPending(hierarchyState)) {
  76. [states addObject:@"LayoutPending"];
  77. }
  78. if (ASHierarchyStateIncludesRasterized(hierarchyState)) {
  79. [states addObject:@"Rasterized"];
  80. }
  81. if (ASHierarchyStateIncludesTransitioningSupernodes(hierarchyState)) {
  82. [states addObject:@"TransitioningSupernodes"];
  83. }
  84. return [NSString stringWithFormat:@"{ %@ }", [states componentsJoinedByString:@" | "]];
  85. }
  86. @interface ASDisplayNode () <ASDescriptionProvider, ASDebugDescriptionProvider>
  87. {
  88. @protected
  89. ASInterfaceState _interfaceState;
  90. ASHierarchyState _hierarchyState;
  91. }
  92. // The view class to use when creating a new display node instance. Defaults to _ASDisplayView.
  93. + (Class)viewClass;
  94. // Thread safe way to access the bounds of the node
  95. @property (nonatomic, assign) CGRect threadSafeBounds;
  96. // These methods are recursive, and either union or remove the provided interfaceState to all sub-elements.
  97. - (void)enterInterfaceState:(ASInterfaceState)interfaceState;
  98. - (void)exitInterfaceState:(ASInterfaceState)interfaceState;
  99. - (void)recursivelySetInterfaceState:(ASInterfaceState)interfaceState;
  100. // These methods are recursive, and either union or remove the provided hierarchyState to all sub-elements.
  101. - (void)enterHierarchyState:(ASHierarchyState)hierarchyState;
  102. - (void)exitHierarchyState:(ASHierarchyState)hierarchyState;
  103. // Changed before calling willEnterHierarchy / didExitHierarchy.
  104. @property (readonly, assign, getter = isInHierarchy) BOOL inHierarchy;
  105. // Call willEnterHierarchy if necessary and set inHierarchy = YES if visibility notifications are enabled on all of its parents
  106. - (void)__enterHierarchy;
  107. // Call didExitHierarchy if necessary and set inHierarchy = NO if visibility notifications are enabled on all of its parents
  108. - (void)__exitHierarchy;
  109. /**
  110. * @abstract Returns the Hierarchy State of the node.
  111. *
  112. * @return The current ASHierarchyState of the node, indicating whether it is rasterized or managed by a range controller.
  113. *
  114. * @see ASInterfaceState
  115. */
  116. @property (nonatomic, readwrite) ASHierarchyState hierarchyState;
  117. /**
  118. * @abstract Return if the node is range managed or not
  119. *
  120. * @discussion Currently only set interface state on nodes in table and collection views. For other nodes, if they are
  121. * in the hierarchy we enable all ASInterfaceState types with `ASInterfaceStateInHierarchy`, otherwise `None`.
  122. */
  123. - (BOOL)supportsRangeManagedInterfaceState;
  124. // The two methods below will eventually be exposed, but their names are subject to change.
  125. /**
  126. * @abstract Ensure that all rendering is complete for this node and its descendants.
  127. *
  128. * @discussion Calling this method on the main thread after a node is added to the view hierarchy will ensure that
  129. * placeholder states are never visible to the user. It is used by ASTableView, ASCollectionView, and ASViewController
  130. * to implement their respective ".neverShowPlaceholders" option.
  131. *
  132. * If all nodes have layer.contents set and/or their layer does not have -needsDisplay set, the method will return immediately.
  133. *
  134. * This method is capable of handling a mixed set of nodes, with some not having started display, some in progress on an
  135. * asynchronous display operation, and some already finished.
  136. *
  137. * In order to guarantee against deadlocks, this method should only be called on the main thread.
  138. * It may block on the private queue, [_ASDisplayLayer displayQueue]
  139. */
  140. - (void)recursivelyEnsureDisplaySynchronously:(BOOL)synchronously;
  141. /**
  142. * @abstract Calls -didExitPreloadState on the receiver and its subnode hierarchy.
  143. *
  144. * @discussion Clears any memory-intensive preloaded content.
  145. * This method is used to notify the node that it should purge any content that is both expensive to fetch and to
  146. * retain in memory.
  147. *
  148. * @see [ASDisplayNode(Subclassing) didExitPreloadState] and [ASDisplayNode(Subclassing) didEnterPreloadState]
  149. */
  150. - (void)recursivelyClearPreloadedData;
  151. /**
  152. * @abstract Calls -didEnterPreloadState on the receiver and its subnode hierarchy.
  153. *
  154. * @discussion Fetches content from remote sources for the current node and all subnodes.
  155. *
  156. * @see [ASDisplayNode(Subclassing) didEnterPreloadState] and [ASDisplayNode(Subclassing) didExitPreloadState]
  157. */
  158. - (void)recursivelyPreload;
  159. /**
  160. * @abstract Triggers a recursive call to -didEnterPreloadState when the node has an interfaceState of ASInterfaceStatePreload
  161. */
  162. - (void)setNeedsPreload;
  163. /**
  164. * @abstract Allows a node to bypass all ensureDisplay passes. Defaults to NO.
  165. *
  166. * @discussion Nodes that are expensive to draw and expected to have placeholder even with
  167. * .neverShowPlaceholders enabled should set this to YES.
  168. *
  169. * ASImageNode uses the default of NO, as it is often used for UI images that are expected to synchronize with ensureDisplay.
  170. *
  171. * ASNetworkImageNode and ASMultiplexImageNode set this to YES, because they load data from a database or server,
  172. * and are expected to support a placeholder state given that display is often blocked on slow data fetching.
  173. */
  174. @property (nonatomic, assign) BOOL shouldBypassEnsureDisplay;
  175. /**
  176. * @abstract Checks whether a node should be scheduled for display, considering its current and new interface states.
  177. */
  178. - (BOOL)shouldScheduleDisplayWithNewInterfaceState:(ASInterfaceState)newInterfaceState;
  179. /**
  180. * @abstract Informs the root node that the intrinsic size of the receiver is no longer valid.
  181. *
  182. * @discussion The size of a root node is determined by each subnode. Calling invalidateSize will let the root node know
  183. * that the intrinsic size of the receiver node is no longer valid and a resizing of the root node needs to happen.
  184. */
  185. - (void)setNeedsLayoutFromAbove;
  186. /**
  187. * @abstract Subclass hook for nodes that are acting as root nodes. This method is called if one of the subnodes
  188. * size is invalidated and may need to result in a different size as the current calculated size.
  189. */
  190. - (void)_locked_displayNodeDidInvalidateSizeNewSize:(CGSize)newSize;
  191. @end
  192. @interface UIView (ASDisplayNodeInternal)
  193. @property (nullable, atomic, weak, readwrite) ASDisplayNode *asyncdisplaykit_node;
  194. @end
  195. @interface CALayer (ASDisplayNodeInternal)
  196. @property (nullable, atomic, weak, readwrite) ASDisplayNode *asyncdisplaykit_node;
  197. @end
  198. NS_ASSUME_NONNULL_END