Add static constant ASInterfaceStateInHierarchy which we'll return if the node is not in a cell but its view is in a window

This commit is contained in:
Adlai Holler
2015-12-04 12:47:36 -08:00
parent 05ff0e40ec
commit 9579420cd7
3 changed files with 54 additions and 10 deletions

View File

@@ -366,7 +366,7 @@
/** /**
* Called just before the view is added to a superview. * Called just before the view is added to a window.
*/ */
- (void)willEnterHierarchy ASDISPLAYNODE_REQUIRES_SUPER; - (void)willEnterHierarchy ASDISPLAYNODE_REQUIRES_SUPER;
@@ -426,9 +426,13 @@
@end @end
@interface ASDisplayNode (ASDisplayNodePrivate) @interface ASDisplayNode (ASDisplayNodePrivate)
// This method has proven helpful in a few rare scenarios, similar to a category extension on UIView, /**
// but it's considered private API for now and its use should not be encouraged. * This method has proven helpful in a few rare scenarios, similar to a category extension on UIView,
- (ASDisplayNode *)_supernodeWithClass:(Class)supernodeClass; * but it's considered private API for now and its use should not be encouraged.
* @param checkViewHierarchy If YES, and no supernode can be found, method will walk up from `self.view` to find a supernode.
* If YES, this method must be called on the main thread and the node must not be layer-backed.
*/
- (ASDisplayNode *)_supernodeWithClass:(Class)supernodeClass checkViewHierarchy:(BOOL)checkViewHierarchy;
// The two methods below will eventually be exposed, but their names are subject to change. // The two methods below will eventually be exposed, but their names are subject to change.
/** /**

View File

@@ -41,18 +41,32 @@ typedef void (^ASDisplayNodeDidLoadBlock)(ASDisplayNode *node);
typedef NS_OPTIONS(NSUInteger, ASInterfaceState) typedef NS_OPTIONS(NSUInteger, ASInterfaceState)
{ {
/** The element is not predicted to be onscreen soon and preloading should not be performed */ /** The element is not predicted to be onscreen soon and preloading should not be performed */
ASInterfaceStateNone = 1 << 0, ASInterfaceStateNone = 0,
/** The element may be added to a view soon that could become visible. Measure the layout, including size calculation. */ /** The element may be added to a view soon that could become visible. Measure the layout, including size calculation. */
ASInterfaceStateMeasureLayout = 1 << 1, ASInterfaceStateMeasureLayout = 1 << 0,
/** The element is likely enough to come onscreen that disk and/or network data required for display should be fetched. */ /** The element is likely enough to come onscreen that disk and/or network data required for display should be fetched. */
ASInterfaceStateFetchData = 1 << 2, ASInterfaceStateFetchData = 1 << 1,
/** The element is very likely to become visible, and concurrent rendering should be executed for any -setNeedsDisplay. */ /** The element is very likely to become visible, and concurrent rendering should be executed for any -setNeedsDisplay. */
ASInterfaceStateDisplay = 1 << 3, ASInterfaceStateDisplay = 1 << 2,
/** The element is physically onscreen by at least 1 pixel. /** 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. */ In practice, all other bit fields should also be set when this flag is set. */
ASInterfaceStateVisible = 1 << 4, ASInterfaceStateVisible = 1 << 3,
}; };
/**
* Currently we only set `interfaceState` for
* nodes contained in table views or collection views.
* Nodes that aren't contained in cells will be in this state when
* they are in the view hierarchy, and `ASInterfaceStateNone` when
* they aren't.
*/
static const ASInterfaceState ASInterfaceStateInHierarchy =
ASInterfaceStateMeasureLayout
| ASInterfaceStateFetchData
| ASInterfaceStateDisplay
| ASInterfaceStateVisible;
/** /**
* An `ASDisplayNode` is an abstraction over `UIView` and `CALayer` that allows you to perform calculations about a view * An `ASDisplayNode` is an abstraction over `UIView` and `CALayer` that allows you to perform calculations about a view
* hierarchy off the main thread, and could do rendering off the main thread as well. * hierarchy off the main thread, and could do rendering off the main thread as well.

View File

@@ -24,6 +24,7 @@
#import "ASInternalHelpers.h" #import "ASInternalHelpers.h"
#import "ASLayout.h" #import "ASLayout.h"
#import "ASLayoutSpec.h" #import "ASLayoutSpec.h"
#import "ASCellNode.h"
@interface ASDisplayNode () <UIGestureRecognizerDelegate> @interface ASDisplayNode () <UIGestureRecognizerDelegate>
@@ -1581,6 +1582,10 @@ void recursivelyEnsureDisplayForLayer(CALayer *layer)
ASDisplayNodeAssertMainThread(); ASDisplayNodeAssertMainThread();
ASDisplayNodeAssert(_flags.isEnteringHierarchy, @"You should never call -willEnterHierarchy directly. Appearance is automatically managed by ASDisplayNode"); ASDisplayNodeAssert(_flags.isEnteringHierarchy, @"You should never call -willEnterHierarchy directly. Appearance is automatically managed by ASDisplayNode");
ASDisplayNodeAssert(!_flags.isExitingHierarchy, @"ASDisplayNode inconsistency. __enterHierarchy and __exitHierarchy are mutually exclusive"); ASDisplayNodeAssert(!_flags.isExitingHierarchy, @"ASDisplayNode inconsistency. __enterHierarchy and __exitHierarchy are mutually exclusive");
if (![self supportsInterfaceState]) {
self.interfaceState = ASInterfaceStateInHierarchy;
}
} }
- (void)didExitHierarchy - (void)didExitHierarchy
@@ -1588,6 +1593,10 @@ void recursivelyEnsureDisplayForLayer(CALayer *layer)
ASDisplayNodeAssertMainThread(); ASDisplayNodeAssertMainThread();
ASDisplayNodeAssert(_flags.isExitingHierarchy, @"You should never call -didExitHierarchy directly. Appearance is automatically managed by ASDisplayNode"); ASDisplayNodeAssert(_flags.isExitingHierarchy, @"You should never call -didExitHierarchy directly. Appearance is automatically managed by ASDisplayNode");
ASDisplayNodeAssert(!_flags.isEnteringHierarchy, @"ASDisplayNode inconsistency. __enterHierarchy and __exitHierarchy are mutually exclusive"); ASDisplayNodeAssert(!_flags.isEnteringHierarchy, @"ASDisplayNode inconsistency. __enterHierarchy and __exitHierarchy are mutually exclusive");
if (![self supportsInterfaceState]) {
self.interfaceState = ASInterfaceStateNone;
}
} }
- (void)clearContents - (void)clearContents
@@ -1635,6 +1644,20 @@ void recursivelyEnsureDisplayForLayer(CALayer *layer)
[self clearFetchedData]; [self clearFetchedData];
} }
/**
* We currently only set interface state on nodes
* in table/collection views. For other nodes, if they are
* in the hierarchy we return `Unknown`, otherwise we return `None`.
*
* TODO: Avoid traversing up node hierarchy due to possible deadlock.
* @see https://github.com/facebook/AsyncDisplayKit/issues/900
* Possible solution is to push `isInCellNode` state downward on `addSubnode`/`removeFromSupernode`.
*/
- (BOOL)supportsInterfaceState {
return ([self isKindOfClass:ASCellNode.class]
|| [self _supernodeWithClass:ASCellNode.class checkViewHierarchy:NO] != nil);
}
- (ASInterfaceState)interfaceState - (ASInterfaceState)interfaceState
{ {
ASDN::MutexLocker l(_propertyLock); ASDN::MutexLocker l(_propertyLock);
@@ -1871,7 +1894,7 @@ void recursivelyEnsureDisplayForLayer(CALayer *layer)
// This method has proved helpful in a few rare scenarios, similar to a category extension on UIView, but assumes knowledge of _ASDisplayView. // This method has proved helpful in a few rare scenarios, similar to a category extension on UIView, but assumes knowledge of _ASDisplayView.
// It's considered private API for now and its use should not be encouraged. // It's considered private API for now and its use should not be encouraged.
- (ASDisplayNode *)_supernodeWithClass:(Class)supernodeClass - (ASDisplayNode *)_supernodeWithClass:(Class)supernodeClass checkViewHierarchy:(BOOL)checkViewHierarchy
{ {
ASDisplayNode *supernode = self.supernode; ASDisplayNode *supernode = self.supernode;
while (supernode) { while (supernode) {
@@ -1879,6 +1902,9 @@ void recursivelyEnsureDisplayForLayer(CALayer *layer)
return supernode; return supernode;
supernode = supernode.supernode; supernode = supernode.supernode;
} }
if (!checkViewHierarchy) {
return nil;
}
UIView *view = self.view.superview; UIView *view = self.view.superview;
while (view) { while (view) {