@@ -197,6 +197,29 @@ + (Class)layerClass
197197 return [_ASDisplayLayer class ];
198198}
199199
200+ + (void )scheduleNodeForDisplay : (ASDisplayNode *)node
201+ {
202+ ASDisplayNodeAssertMainThread ();
203+ static NSMutableSet *nodesToDisplay = nil ;
204+ static BOOL displayScheduled = NO ;
205+ if (!nodesToDisplay) {
206+ nodesToDisplay = [[NSMutableSet alloc ] init ];
207+ }
208+ [nodesToDisplay addObject: node];
209+ if (!displayScheduled) {
210+ displayScheduled = YES ;
211+ // It's essenital that any layout pass that is scheduled during the current
212+ // runloop has a chance to be applied / scheduled, so always perform this after the current runloop.
213+ dispatch_async (dispatch_get_main_queue (), ^{
214+ displayScheduled = NO ;
215+ for (ASDisplayNode *node in nodesToDisplay) {
216+ [node __recursivelyTriggerDisplayAndBlock: NO ];
217+ }
218+ nodesToDisplay = nil ;
219+ });
220+ }
221+ }
222+
200223#pragma mark - Lifecycle
201224
202225- (void )_staticInitialize
@@ -710,6 +733,7 @@ - (void)displayImmediately
710733- (void )recursivelyDisplayImmediately
711734{
712735 ASDN::MutexLocker l (_propertyLock);
736+
713737 for (ASDisplayNode *child in _subnodes) {
714738 [child recursivelyDisplayImmediately ];
715739 }
@@ -1453,7 +1477,7 @@ - (void)_tearDownPlaceholderLayer
14531477 [_placeholderLayer removeFromSuperlayer ];
14541478}
14551479
1456- void recursivelyEnsureDisplayForLayer (CALayer *layer)
1480+ void recursivelyTriggerDisplayForLayer (CALayer *layer, BOOL shouldBlock )
14571481{
14581482 // This recursion must handle layers in various states:
14591483 // 1. Just added to hierarchy, CA hasn't yet called -display
@@ -1472,26 +1496,26 @@ void recursivelyEnsureDisplayForLayer(CALayer *layer)
14721496
14731497 // Kick off the recursion first, so that all necessary display calls are sent and the displayQueue is full of parallelizable work.
14741498 for (CALayer *sublayer in layer.sublayers ) {
1475- recursivelyEnsureDisplayForLayer (sublayer);
1499+ recursivelyTriggerDisplayForLayer (sublayer, shouldBlock );
14761500 }
14771501
1478- // As the recursion unwinds, verify each transaction is complete and block if it is not.
1479- // While blocking on one transaction, others may be completing concurrently, so it doesn't matter which blocks first.
1480- BOOL waitUntilComplete = (!node.shouldBypassEnsureDisplay );
1481- if (waitUntilComplete) {
1482- for (_ASAsyncTransaction *transaction in [layer.asyncdisplaykit_asyncLayerTransactions copy ]) {
1483- // Even if none of the layers have had a chance to start display earlier, they will still be allowed to saturate a multicore CPU while blocking main.
1484- // This significantly reduces time on the main thread relative to UIKit.
1485- [transaction waitUntilComplete ];
1502+ if (shouldBlock) {
1503+ // As the recursion unwinds, verify each transaction is complete and block if it is not.
1504+ // While blocking on one transaction, others may be completing concurrently, so it doesn't matter which blocks first.
1505+ BOOL waitUntilComplete = (!node.shouldBypassEnsureDisplay );
1506+ if (waitUntilComplete) {
1507+ for (_ASAsyncTransaction *transaction in [layer.asyncdisplaykit_asyncLayerTransactions copy ]) {
1508+ // Even if none of the layers have had a chance to start display earlier, they will still be allowed to saturate a multicore CPU while blocking main.
1509+ // This significantly reduces time on the main thread relative to UIKit.
1510+ [transaction waitUntilComplete ];
1511+ }
14861512 }
14871513 }
14881514}
14891515
1490- - (void )recursivelyEnsureDisplay
1516+ - (void )__recursivelyTriggerDisplayAndBlock : ( BOOL ) shouldBlock
14911517{
14921518 ASDisplayNodeAssertMainThread ();
1493- ASDisplayNodeAssert (self.isNodeLoaded , @" Node must have layer or view loaded to use -recursivelyEnsureDisplay" );
1494- ASDisplayNodeAssert (self.inHierarchy && (self.isLayerBacked || self.view .window != nil ), @" Node must be in a hierarchy to use -recursivelyEnsureDisplay" );
14951519
14961520 CALayer *layer = self.layer ;
14971521 // -layoutIfNeeded is recursive, and even walks up to superlayers to check if they need layout,
@@ -1500,7 +1524,12 @@ - (void)recursivelyEnsureDisplay
15001524 if ([layer needsLayout ]) {
15011525 [layer layoutIfNeeded ];
15021526 }
1503- recursivelyEnsureDisplayForLayer (layer);
1527+ recursivelyTriggerDisplayForLayer (layer, shouldBlock);
1528+ }
1529+
1530+ - (void )recursivelyEnsureDisplay
1531+ {
1532+ [self __recursivelyTriggerDisplayAndBlock: YES ];
15041533}
15051534
15061535- (void )setShouldBypassEnsureDisplay : (BOOL )shouldBypassEnsureDisplay
@@ -2127,6 +2156,9 @@ - (BOOL)_isMarkedForReplacement
21272156 return _replaceAsyncSentinel != nil ;
21282157}
21292158
2159+ // FIXME: This method doesn't appear to be called, and could be removed.
2160+ // However, it may be useful for an API similar to what Paper used to create a new node hierarchy,
2161+ // trigger asynchronous measurement and display on it, and have it swap out and replace an old hierarchy.
21302162- (ASSentinel *)_asyncReplaceSentinel
21312163{
21322164 ASDN::MutexLocker l (_propertyLock);
0 commit comments