Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve Our Handling of Subnodes #223

Merged
merged 3 commits into from
May 2, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@
- [Yoga Beta] Improvements to the experimental support for Yoga layout [Scott Goodson](appleguy)
- Update the rasterization API and un-deprecate it. [Adlai Holler](https://github.com/Adlai-Holler)[#82](https://github.com/TextureGroup/Texture/pull/49)
- Simplified & optimized hashing code. [Adlai Holler](https://github.com/Adlai-Holler) [#86](https://github.com/TextureGroup/Texture/pull/86)
- Improve the performance & safety of ASDisplayNode subnodes. [Adlai Holler](https://github.com/Adlai-Holler) [#223](https://github.com/TextureGroup/Texture/pull/223)
2 changes: 1 addition & 1 deletion Source/ASDisplayNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ extern NSInteger const ASDefaultDrawingPriority;
*
*/

@interface ASDisplayNode : NSObject <ASLayoutElement, ASLayoutElementStylability, NSFastEnumeration>
@interface ASDisplayNode : NSObject <ASLayoutElement, ASLayoutElementStylability>

/** @name Initializing a node object */

Expand Down
24 changes: 10 additions & 14 deletions Source/ASDisplayNode.mm
Original file line number Diff line number Diff line change
Expand Up @@ -430,8 +430,6 @@ - (void)dealloc
[self _scheduleIvarsForMainDeallocation];
}

_subnodes = nil;

#if YOGA
if (_yogaNode != NULL) {
YGNodeFree(_yogaNode);
Expand Down Expand Up @@ -1411,17 +1409,15 @@ - (void)_layoutSublayouts
ASDisplayNodeAssertLockUnownedByCurrentThread(__instanceLock__);

ASLayout *layout;
NSArray<ASDisplayNode *> *subnodes;
{
ASDN::MutexLocker l(__instanceLock__);
if (_calculatedDisplayNodeLayout->isDirty() || _subnodes.count == 0) {
if (_calculatedDisplayNodeLayout->isDirty()) {
return;
}
layout = _calculatedDisplayNodeLayout->layout;
subnodes = [_subnodes copy];
}

for (ASDisplayNode *node in subnodes) {
for (ASDisplayNode *node in self.subnodes) {
CGRect frame = [layout frameForElement:node];
if (CGRectIsNull(frame)) {
// There is no frame for this node in our layout.
Expand Down Expand Up @@ -2675,7 +2671,12 @@ - (void)_setSupernode:(ASDisplayNode *)newSupernode
- (NSArray *)subnodes
{
ASDN::MutexLocker l(__instanceLock__);
return ([_subnodes copy] ?: @[]);
if (_cachedSubnodes == nil) {
_cachedSubnodes = [_subnodes copy];
} else {
ASDisplayNodeAssert(ASObjectIsEqual(_cachedSubnodes, _subnodes), @"Expected _subnodes and _cachedSubnodes to have the same contents.");
}
return _cachedSubnodes ?: @[];
}

/*
Expand Down Expand Up @@ -2736,6 +2737,7 @@ - (void)_insertSubnode:(ASDisplayNode *)subnode atSubnodeIndex:(NSInteger)subnod
_subnodes = [[NSMutableArray alloc] init];
}
[_subnodes insertObject:subnode atIndex:subnodeIndex];
_cachedSubnodes = nil;
__instanceLock__.unlock();

// This call will apply our .hierarchyState to the new subnode.
Expand Down Expand Up @@ -3071,6 +3073,7 @@ - (void)_removeSubnode:(ASDisplayNode *)subnode

__instanceLock__.lock();
[_subnodes removeObjectIdenticalTo:subnode];
_cachedSubnodes = nil;
__instanceLock__.unlock();

[subnode _setSupernode:nil];
Expand Down Expand Up @@ -4060,13 +4063,6 @@ - (CGRect)_frameInWindow
}
}

#pragma mark - NSFastEnumeration

- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id __unsafe_unretained _Nullable [_Nonnull])buffer count:(NSUInteger)len
{
return [self.subnodes countByEnumeratingWithState:state objects:buffer count:len];
}

#pragma mark - ASPrimitiveTraitCollection

- (ASPrimitiveTraitCollection)primitiveTraitCollection
Expand Down
3 changes: 3 additions & 0 deletions Source/Private/ASDisplayNodeInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,9 @@ FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayNodesScheduledBefo
ASDisplayNode * __weak _supernode;
NSMutableArray<ASDisplayNode *> *_subnodes;

// Set this to nil whenever you modify _subnodes
NSArray<ASDisplayNode *> *_cachedSubnodes;
Copy link
Member

@garrettmoon garrettmoon May 2, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a dangerous optimization. Could we at least put in an assert that _subnodes and _cachedSubnodes have the same content in the subnodes getter?


ASLayoutElementStyle *_style;
ASPrimitiveTraitCollection _primitiveTraitCollection;

Expand Down