mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-16 11:20:18 +00:00
Merge pull request #1053 from facebook/ASRangeControllerBetaOptimizations
Substantial optimizations for ASRangeControllerBeta & recursivelySetInterfaceState:.
This commit is contained in:
commit
516e1f177d
@ -495,6 +495,13 @@
|
||||
remoteGlobalIDString = 058D09AB195D04C000B7D73C;
|
||||
remoteInfo = AsyncDisplayKit;
|
||||
};
|
||||
DEACA2B11C425DC400FA9DDF /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 058D09A4195D04C000B7D73C /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 058D09AB195D04C000B7D73C;
|
||||
remoteInfo = AsyncDisplayKit;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
@ -1524,6 +1531,7 @@
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
DEACA2B21C425DC400FA9DDF /* PBXTargetDependency */,
|
||||
);
|
||||
name = AsyncDisplayKitTestHost;
|
||||
productName = AsyncDisplayKitTestHost;
|
||||
@ -1939,6 +1947,11 @@
|
||||
target = 058D09AB195D04C000B7D73C /* AsyncDisplayKit */;
|
||||
targetProxy = 058D09C2195D04C000B7D73C /* PBXContainerItemProxy */;
|
||||
};
|
||||
DEACA2B21C425DC400FA9DDF /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 058D09AB195D04C000B7D73C /* AsyncDisplayKit */;
|
||||
targetProxy = DEACA2B11C425DC400FA9DDF /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
|
||||
@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
@ -198,12 +198,14 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
||||
return [_ASDisplayLayer class];
|
||||
}
|
||||
|
||||
+ (void)scheduleNodeForDisplay:(ASDisplayNode *)node
|
||||
+ (void)scheduleNodeForRecursiveDisplay:(ASDisplayNode *)node
|
||||
{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
ASDisplayNodeAssert([ASDisplayNode shouldUseNewRenderingRange], @"+scheduleNodeForRecursiveDisplay: should never be called without the new rendering range enabled");
|
||||
static NSMutableSet *nodesToDisplay = nil;
|
||||
static BOOL displayScheduled = NO;
|
||||
static ASDN::RecursiveMutex displaySchedulerLock;
|
||||
|
||||
{
|
||||
ASDN::MutexLocker l(displaySchedulerLock);
|
||||
if (!nodesToDisplay) {
|
||||
@ -211,6 +213,7 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
||||
}
|
||||
[nodesToDisplay addObject:node];
|
||||
}
|
||||
|
||||
if (!displayScheduled) {
|
||||
displayScheduled = YES;
|
||||
// It's essenital that any layout pass that is scheduled during the current
|
||||
@ -1557,13 +1560,11 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
|
||||
|
||||
- (void)setShouldBypassEnsureDisplay:(BOOL)shouldBypassEnsureDisplay
|
||||
{
|
||||
ASDN::MutexLocker l(_propertyLock);
|
||||
_flags.shouldBypassEnsureDisplay = shouldBypassEnsureDisplay;
|
||||
}
|
||||
|
||||
- (BOOL)shouldBypassEnsureDisplay
|
||||
{
|
||||
ASDN::MutexLocker l(_propertyLock);
|
||||
return _flags.shouldBypassEnsureDisplay;
|
||||
}
|
||||
|
||||
@ -1612,7 +1613,7 @@ static BOOL ShouldUseNewRenderingRange = NO;
|
||||
- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize
|
||||
{
|
||||
ASDisplayNodeAssertThreadAffinity(self);
|
||||
return [ASLayoutSpec new];
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (ASLayout *)calculatedLayout
|
||||
@ -1782,8 +1783,11 @@ static BOOL ShouldUseNewRenderingRange = NO;
|
||||
// Still, the interfaceState should be updated to the current state of the node; just don't act on the transition.
|
||||
|
||||
// Entered or exited data loading state.
|
||||
if ((newState & ASInterfaceStateFetchData) != (oldState & ASInterfaceStateFetchData)) {
|
||||
if (newState & ASInterfaceStateFetchData) {
|
||||
BOOL nowFetchData = ASInterfaceStateIncludesFetchData(newState);
|
||||
BOOL wasFetchData = ASInterfaceStateIncludesFetchData(oldState);
|
||||
|
||||
if (nowFetchData != wasFetchData) {
|
||||
if (nowFetchData) {
|
||||
[self fetchData];
|
||||
} else {
|
||||
if ([self supportsRangeManagedInterfaceState]) {
|
||||
@ -1793,21 +1797,42 @@ static BOOL ShouldUseNewRenderingRange = NO;
|
||||
}
|
||||
|
||||
// Entered or exited contents rendering state.
|
||||
if ((newState & ASInterfaceStateDisplay) != (oldState & ASInterfaceStateDisplay)) {
|
||||
BOOL nowDisplay = ASInterfaceStateIncludesDisplay(newState);
|
||||
BOOL wasDisplay = ASInterfaceStateIncludesDisplay(oldState);
|
||||
|
||||
if (nowDisplay != wasDisplay) {
|
||||
if ([self supportsRangeManagedInterfaceState]) {
|
||||
if (newState & ASInterfaceStateDisplay) {
|
||||
if (nowDisplay) {
|
||||
// Once the working window is eliminated (ASRangeHandlerRender), trigger display directly here.
|
||||
[self setDisplaySuspended:NO];
|
||||
} else {
|
||||
[self setDisplaySuspended:YES];
|
||||
[self clearContents];
|
||||
}
|
||||
} else {
|
||||
// NOTE: This case isn't currently supported as setInterfaceState: isn't exposed externally, and all
|
||||
// internal use cases are range-managed. When a node is visible, don't mess with display - CA will start it.
|
||||
if ([ASDisplayNode shouldUseNewRenderingRange] && !ASInterfaceStateIncludesVisible(newState)) {
|
||||
// Check __implementsDisplay purely for efficiency - it's faster even than calling -asyncLayer.
|
||||
if ([self __implementsDisplay]) {
|
||||
if (nowDisplay) {
|
||||
[ASDisplayNode scheduleNodeForRecursiveDisplay:self];
|
||||
} else {
|
||||
[[self asyncLayer] cancelAsyncDisplay];
|
||||
[self clearContents];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Entered or exited data loading state.
|
||||
if ((newState & ASInterfaceStateVisible) != (oldState & ASInterfaceStateVisible)) {
|
||||
if (newState & ASInterfaceStateVisible) {
|
||||
// Became visible or invisible. When range-managed, this represents literal visibility - at least one pixel
|
||||
// is onscreen. If not range-managed, we can't guarantee more than the node being present in an onscreen window.
|
||||
BOOL nowVisible = ASInterfaceStateIncludesVisible(newState);
|
||||
BOOL wasVisible = ASInterfaceStateIncludesVisible(oldState);
|
||||
|
||||
if (nowVisible != wasVisible) {
|
||||
if (nowVisible) {
|
||||
[self visibilityDidChange:YES];
|
||||
} else {
|
||||
[self visibilityDidChange:NO];
|
||||
@ -1843,11 +1868,23 @@ static BOOL ShouldUseNewRenderingRange = NO;
|
||||
|
||||
- (void)recursivelySetInterfaceState:(ASInterfaceState)interfaceState
|
||||
{
|
||||
ASInterfaceState oldState = self.interfaceState;
|
||||
ASInterfaceState newState = interfaceState;
|
||||
ASDisplayNodePerformBlockOnEveryNode(nil, self, ^(ASDisplayNode *node) {
|
||||
node.interfaceState = interfaceState;
|
||||
});
|
||||
// FIXME: This should also be called in setInterfaceState: if it isn't being applied recursively.
|
||||
[ASDisplayNode scheduleNodeForDisplay:self];
|
||||
|
||||
if ([self supportsRangeManagedInterfaceState]) {
|
||||
// Instead of each node in the recursion assuming it needs to schedule itself for display,
|
||||
// setInterfaceState: skips this when handling range-managed nodes (our whole subtree has this set).
|
||||
// If our range manager intends for us to be displayed right now, and didn't before, get started!
|
||||
|
||||
BOOL nowDisplay = ASInterfaceStateIncludesDisplay(newState);
|
||||
BOOL wasDisplay = ASInterfaceStateIncludesDisplay(oldState);
|
||||
if (nowDisplay && (nowDisplay != wasDisplay)) {
|
||||
[ASDisplayNode scheduleNodeForRecursiveDisplay:self];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (ASHierarchyState)hierarchyState
|
||||
|
||||
@ -12,6 +12,23 @@
|
||||
#import <AsyncDisplayKit/ASBaseDefines.h>
|
||||
#import <AsyncDisplayKit/ASDisplayNode.h>
|
||||
|
||||
// Because inline methods can't be extern'd and need to be part of the translation unit of code
|
||||
// that compiles with them to actually inline, we both declare and define these in the header.
|
||||
inline BOOL ASInterfaceStateIncludesVisible(ASInterfaceState interfaceState)
|
||||
{
|
||||
return ((interfaceState & ASInterfaceStateVisible) == ASInterfaceStateVisible);
|
||||
}
|
||||
|
||||
inline BOOL ASInterfaceStateIncludesDisplay(ASInterfaceState interfaceState)
|
||||
{
|
||||
return ((interfaceState & ASInterfaceStateDisplay) == ASInterfaceStateDisplay);
|
||||
}
|
||||
|
||||
inline BOOL ASInterfaceStateIncludesFetchData(ASInterfaceState interfaceState)
|
||||
{
|
||||
return ((interfaceState & ASInterfaceStateFetchData) == ASInterfaceStateFetchData);
|
||||
}
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
ASDISPLAYNODE_EXTERN_C_BEGIN
|
||||
|
||||
@ -17,21 +17,6 @@
|
||||
#import "ASInternalHelpers.h"
|
||||
#import "ASDisplayNode+FrameworkPrivate.h"
|
||||
|
||||
extern BOOL ASInterfaceStateIncludesVisible(ASInterfaceState interfaceState)
|
||||
{
|
||||
return ((interfaceState & ASInterfaceStateVisible) == ASInterfaceStateVisible);
|
||||
}
|
||||
|
||||
extern BOOL ASInterfaceStateIncludesDisplay(ASInterfaceState interfaceState)
|
||||
{
|
||||
return ((interfaceState & ASInterfaceStateDisplay) == ASInterfaceStateDisplay);
|
||||
}
|
||||
|
||||
extern BOOL ASInterfaceStateIncludesFetchData(ASInterfaceState interfaceState)
|
||||
{
|
||||
return ((interfaceState & ASInterfaceStateFetchData) == ASInterfaceStateFetchData);
|
||||
}
|
||||
|
||||
@interface ASRangeControllerBeta ()
|
||||
{
|
||||
BOOL _rangeIsValid;
|
||||
@ -95,23 +80,34 @@ extern BOOL ASInterfaceStateIncludesFetchData(ASInterfaceState interfaceState)
|
||||
[_layoutController setVisibleNodeIndexPaths:visibleNodePaths];
|
||||
}
|
||||
|
||||
NSArray *allNodes = [_dataSource completedNodes];
|
||||
NSArray *currentSectionNodes = nil;
|
||||
NSInteger currentSectionIndex = -1; // Will be unequal to any indexPath.section, so we set currentSectionNodes.
|
||||
|
||||
NSUInteger numberOfSections = [allNodes count];
|
||||
NSUInteger numberOfNodesInSection = 0;
|
||||
|
||||
NSSet *visibleIndexPaths = [NSSet setWithArray:visibleNodePaths];
|
||||
// = [_layoutController indexPathsForScrolling:_scrollDirection rangeType:ASLayoutRangeTypeVisible];
|
||||
NSSet *displayIndexPaths = nil;
|
||||
NSSet *fetchDataIndexPaths = nil;
|
||||
NSMutableSet *allIndexPaths = nil;
|
||||
NSMutableArray *modifiedIndexPaths = (RangeControllerLoggingEnabled ? [NSMutableArray array] : nil);
|
||||
|
||||
ASInterfaceState selfInterfaceState = [_dataSource interfaceStateForRangeController:self];
|
||||
|
||||
NSSet *visibleIndexPaths = [_layoutController indexPathsForScrolling:_scrollDirection rangeType:ASLayoutRangeTypeVisible];
|
||||
|
||||
#if RangeControllerLoggingEnabled
|
||||
NSMutableArray *modified = [NSMutableArray array];
|
||||
#endif
|
||||
|
||||
if (ASInterfaceStateIncludesVisible(selfInterfaceState)) {
|
||||
// If we are already visible, get busy! Better get started on preloading before the user scrolls more...
|
||||
NSSet *fetchDataIndexPaths = [_layoutController indexPathsForScrolling:_scrollDirection rangeType:ASLayoutRangeTypeFetchData];
|
||||
NSSet *displayIndexPaths = [_layoutController indexPathsForScrolling:_scrollDirection rangeType:ASLayoutRangeTypeDisplay];
|
||||
fetchDataIndexPaths = [_layoutController indexPathsForScrolling:_scrollDirection rangeType:ASLayoutRangeTypeFetchData];
|
||||
displayIndexPaths = [_layoutController indexPathsForScrolling:_scrollDirection rangeType:ASLayoutRangeTypeDisplay];
|
||||
|
||||
// Typically the fetchDataIndexPaths will be the largest, and be a superset of the others, though it may be disjoint.
|
||||
NSMutableSet *allIndexPaths = [fetchDataIndexPaths mutableCopy];
|
||||
allIndexPaths = [fetchDataIndexPaths mutableCopy];
|
||||
[allIndexPaths unionSet:displayIndexPaths];
|
||||
[allIndexPaths unionSet:visibleIndexPaths];
|
||||
} else {
|
||||
allIndexPaths = [visibleIndexPaths mutableCopy];
|
||||
}
|
||||
|
||||
// Sets are magical. Add anything we had applied interfaceState to in the last update, so we can clear any
|
||||
// range flags it still has enabled. Most of the time, all but a few elements are equal; a large programmatic
|
||||
@ -125,6 +121,7 @@ extern BOOL ASInterfaceStateIncludesFetchData(ASInterfaceState interfaceState)
|
||||
// For consistency, make sure each node knows that it should measure itself if something changes.
|
||||
ASInterfaceState interfaceState = ASInterfaceStateMeasureLayout;
|
||||
|
||||
if (ASInterfaceStateIncludesVisible(selfInterfaceState)) {
|
||||
if ([fetchDataIndexPaths containsObject:indexPath]) {
|
||||
interfaceState |= ASInterfaceStateFetchData;
|
||||
}
|
||||
@ -134,38 +131,48 @@ extern BOOL ASInterfaceStateIncludesFetchData(ASInterfaceState interfaceState)
|
||||
if ([visibleIndexPaths containsObject:indexPath]) {
|
||||
interfaceState |= ASInterfaceStateVisible;
|
||||
}
|
||||
|
||||
ASDisplayNode *node = [_dataSource rangeController:self nodeAtIndexPath:indexPath];
|
||||
ASDisplayNodeAssert(node.hierarchyState & ASHierarchyStateRangeManaged, @"All nodes reaching this point should be range-managed, or interfaceState may be incorrectly reset.");
|
||||
// Skip the many method calls of the recursive operation if the top level cell node already has the right interfaceState.
|
||||
if (node.interfaceState != interfaceState) {
|
||||
#if RangeControllerLoggingEnabled
|
||||
[modified addObject:indexPath];
|
||||
#endif
|
||||
[node recursivelySetInterfaceState:interfaceState];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If selfInterfaceState isn't visible, then visibleIndexPaths represents what /will/ be immediately visible at the
|
||||
// instant we come onscreen. So, fetch data and display all of those things, but don't waste resources preloading yet.
|
||||
// We handle this as a separate case to minimize set operations for offscreen preloading, including containsObject:.
|
||||
|
||||
for (NSIndexPath *indexPath in visibleIndexPaths) {
|
||||
// Set Layout, Fetch Data, Display. DO NOT set Visible: even though these elements are in the visible range / "viewport",
|
||||
// our overall container object is itself not visible yet. The moment it becomes visible, we will run the condition above.
|
||||
ASInterfaceState interfaceState = ASInterfaceStateMeasureLayout | ASInterfaceStateFetchData | ASInterfaceStateDisplay;
|
||||
if ([allCurrentIndexPaths containsObject:indexPath]) {
|
||||
// We might be looking at an indexPath that was previously in-range, but now we need to clear it.
|
||||
// In that case we'll just set it back to MeasureLayout. Only set Display | FetchData if in allCurrentIndexPaths.
|
||||
interfaceState |= ASInterfaceStateDisplay;
|
||||
interfaceState |= ASInterfaceStateFetchData;
|
||||
}
|
||||
}
|
||||
|
||||
NSInteger section = indexPath.section;
|
||||
NSInteger row = indexPath.row;
|
||||
|
||||
if (section >= 0 && row >= 0 && section < numberOfSections) {
|
||||
if (section != currentSectionIndex) {
|
||||
// Often we'll be dealing with indexPaths in the same section, but the set isn't sorted and we may even bounce
|
||||
// between the same ones. Still, this saves dozens of method calls to access the inner array and count.
|
||||
currentSectionNodes = [allNodes objectAtIndex:section];
|
||||
numberOfNodesInSection = [currentSectionNodes count];
|
||||
currentSectionIndex = section;
|
||||
}
|
||||
|
||||
if (row < numberOfNodesInSection) {
|
||||
ASDisplayNode *node = [currentSectionNodes objectAtIndex:row];
|
||||
|
||||
ASDisplayNode *node = [_dataSource rangeController:self nodeAtIndexPath:indexPath];
|
||||
ASDisplayNodeAssert(node.hierarchyState & ASHierarchyStateRangeManaged, @"All nodes reaching this point should be range-managed, or interfaceState may be incorrectly reset.");
|
||||
// Skip the many method calls of the recursive operation if the top level cell node already has the right interfaceState.
|
||||
if (node.interfaceState != interfaceState) {
|
||||
#if RangeControllerLoggingEnabled
|
||||
[modified addObject:indexPath];
|
||||
#endif
|
||||
[modifiedIndexPaths addObject:indexPath];
|
||||
[node recursivelySetInterfaceState:interfaceState];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_rangeIsValid = YES;
|
||||
_queuedRangeUpdate = NO;
|
||||
|
||||
#if RangeControllerLoggingEnabled
|
||||
NSSet *visibleNodePathsSet = [NSSet setWithArray:visibleNodePaths];
|
||||
@ -176,9 +183,9 @@ extern BOOL ASInterfaceStateIncludesFetchData(ASInterfaceState interfaceState)
|
||||
NSLog(@"custom: %@", visibleNodePathsSet);
|
||||
}
|
||||
|
||||
[modified sortUsingSelector:@selector(compare:)];
|
||||
[modifiedIndexPaths sortUsingSelector:@selector(compare:)];
|
||||
|
||||
for (NSIndexPath *indexPath in modified) {
|
||||
for (NSIndexPath *indexPath in modifiedIndexPaths) {
|
||||
ASDisplayNode *node = [_dataSource rangeController:self nodeAtIndexPath:indexPath];
|
||||
ASInterfaceState interfaceState = node.interfaceState;
|
||||
BOOL inVisible = ASInterfaceStateIncludesVisible(interfaceState);
|
||||
@ -187,9 +194,6 @@ extern BOOL ASInterfaceStateIncludesFetchData(ASInterfaceState interfaceState)
|
||||
NSLog(@"indexPath %@, Visible: %d, Display: %d, FetchData: %d", indexPath, inVisible, inDisplay, inFetchData);
|
||||
}
|
||||
#endif
|
||||
|
||||
_rangeIsValid = YES;
|
||||
_queuedRangeUpdate = NO;
|
||||
}
|
||||
|
||||
#pragma mark - Cell node view handling
|
||||
|
||||
@ -110,6 +110,8 @@
|
||||
ASDisplayNodeAssertMainThread();
|
||||
|
||||
ASDN::MutexLocker l(_displaySuspendedLock);
|
||||
// FIXME: Reconsider whether we should cancel a display in progress.
|
||||
// We should definitely cancel a display that is scheduled, but unstarted display.
|
||||
[self cancelAsyncDisplay];
|
||||
|
||||
// Short circuit if display is suspended. When resumed, we will setNeedsDisplay at that time.
|
||||
|
||||
@ -39,7 +39,6 @@ static NSString * const kDefaultChildrenKey = @"kDefaultChildrenKey";
|
||||
if (!(self = [super init])) {
|
||||
return nil;
|
||||
}
|
||||
_layoutChildren = [NSMutableDictionary dictionary];
|
||||
_isMutable = YES;
|
||||
return self;
|
||||
}
|
||||
@ -56,11 +55,6 @@ static NSString * const kDefaultChildrenKey = @"kDefaultChildrenKey";
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setChild:(id<ASLayoutable>)child;
|
||||
{
|
||||
[self setChild:child forIdentifier:kDefaultChildKey];
|
||||
}
|
||||
|
||||
- (id<ASLayoutable>)layoutableToAddFromLayoutable:(id<ASLayoutable>)child
|
||||
{
|
||||
if (self.isFinalLayoutable == NO) {
|
||||
@ -88,6 +82,19 @@ static NSString * const kDefaultChildrenKey = @"kDefaultChildrenKey";
|
||||
return child;
|
||||
}
|
||||
|
||||
- (NSMutableDictionary *)layoutChildren
|
||||
{
|
||||
if (!_layoutChildren) {
|
||||
_layoutChildren = [NSMutableDictionary dictionary];
|
||||
}
|
||||
return _layoutChildren;
|
||||
}
|
||||
|
||||
- (void)setChild:(id<ASLayoutable>)child;
|
||||
{
|
||||
[self setChild:child forIdentifier:kDefaultChildKey];
|
||||
}
|
||||
|
||||
- (void)setChild:(id<ASLayoutable>)child forIdentifier:(NSString *)identifier
|
||||
{
|
||||
ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable");
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
#import "ASInternalHelpers.h"
|
||||
#import "ASAssert.h"
|
||||
#import "ASDisplayNodeInternal.h"
|
||||
#import "ASDisplayNodeExtras.h"
|
||||
#import "ASDisplayNode+Subclasses.h"
|
||||
#import "ASDisplayNode+FrameworkPrivate.h"
|
||||
#import "ASDisplayNode+Beta.h"
|
||||
@ -250,9 +251,11 @@
|
||||
_messageToViewOrLayer(setNeedsDisplay);
|
||||
|
||||
if ([ASDisplayNode shouldUseNewRenderingRange]) {
|
||||
BOOL shouldDisplay = ((_interfaceState & ASInterfaceStateDisplay) == ASInterfaceStateDisplay);
|
||||
if (_layer && !_flags.synchronous && shouldDisplay) {
|
||||
[ASDisplayNode scheduleNodeForDisplay:self];
|
||||
BOOL nowDisplay = ASInterfaceStateIncludesDisplay(_interfaceState);
|
||||
// FIXME: This should not need to recursively display, so create a non-recursive variant.
|
||||
// The semantics of setNeedsDisplay (as defined by CALayer behavior) are not recursive.
|
||||
if (_layer && !_flags.synchronous && nowDisplay && [self __implementsDisplay]) {
|
||||
[ASDisplayNode scheduleNodeForRecursiveDisplay:self];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,7 +109,7 @@ typedef NS_OPTIONS(NSUInteger, ASDisplayNodeMethodOverrides)
|
||||
#endif
|
||||
}
|
||||
|
||||
+ (void)scheduleNodeForDisplay:(ASDisplayNode *)node;
|
||||
+ (void)scheduleNodeForRecursiveDisplay:(ASDisplayNode *)node;
|
||||
|
||||
// The _ASDisplayLayer backing the node, if any.
|
||||
@property (nonatomic, readonly, retain) _ASDisplayLayer *asyncLayer;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user