Copy yogaChildren in accessor method. Avoid using accessor method internally (#1283)

* Copy yogaChildren in accessor method. Avoid using accessor method internally.

* Further improvements
This commit is contained in:
Michael Schneider 2018-12-20 17:45:52 +01:00 committed by GitHub
parent 4982c84640
commit ab0a00c21c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 31 additions and 10 deletions

View File

@ -188,8 +188,7 @@ AS_EXTERN void ASDisplayNodePerformBlockOnEveryYogaChild(ASDisplayNode * _Nullab
@interface ASDisplayNode (Yoga)
// TODO: Make this and yogaCalculatedLayout atomic (lock).
@property (nullable, nonatomic) NSArray *yogaChildren;
@property (copy) NSArray *yogaChildren;
- (void)addYogaChild:(ASDisplayNode *)child;
- (void)removeYogaChild:(ASDisplayNode *)child;
@ -198,6 +197,7 @@ AS_EXTERN void ASDisplayNodePerformBlockOnEveryYogaChild(ASDisplayNode * _Nullab
- (void)semanticContentAttributeDidChange:(UISemanticContentAttribute)attribute;
@property BOOL yogaLayoutInProgress;
// TODO: Make this atomic (lock).
@property (nullable, nonatomic) ASLayout *yogaCalculatedLayout;
// Will walk up the Yoga tree and returns the root node

View File

@ -48,32 +48,43 @@
for (ASDisplayNode *child in [_yogaChildren copy]) {
// Make sure to un-associate the YGNodeRef tree before replacing _yogaChildren
// If this becomes a performance bottleneck, it can be optimized by not doing the NSArray removals here.
[self removeYogaChild:child];
[self _locked_removeYogaChild:child];
}
_yogaChildren = nil;
for (ASDisplayNode *child in yogaChildren) {
[self addYogaChild:child];
[self _locked_addYogaChild:child];
}
}
- (NSArray *)yogaChildren
{
return _yogaChildren;
ASLockScope(self.yogaRoot);
return [_yogaChildren copy] ?: @[];
}
- (void)addYogaChild:(ASDisplayNode *)child
{
ASLockScope(self.yogaRoot);
[self _locked_addYogaChild:child];
}
- (void)_locked_addYogaChild:(ASDisplayNode *)child
{
[self insertYogaChild:child atIndex:_yogaChildren.count];
}
- (void)removeYogaChild:(ASDisplayNode *)child
{
ASLockScope(self.yogaRoot);
[self _locked_removeYogaChild:child];
}
- (void)_locked_removeYogaChild:(ASDisplayNode *)child
{
if (child == nil) {
return;
}
[_yogaChildren removeObjectIdenticalTo:child];
// YGNodeRef removal is done in setParent:
@ -83,6 +94,11 @@
- (void)insertYogaChild:(ASDisplayNode *)child atIndex:(NSUInteger)index
{
ASLockScope(self.yogaRoot);
[self _locked_insertYogaChild:child atIndex:index];
}
- (void)_locked_insertYogaChild:(ASDisplayNode *)child atIndex:(NSUInteger)index
{
if (child == nil) {
return;
}
@ -91,7 +107,7 @@
}
// Clean up state in case this child had another parent.
[self removeYogaChild:child];
[self _locked_removeYogaChild:child];
[_yogaChildren insertObject:child atIndex:index];
@ -99,6 +115,8 @@
child.yogaParent = self;
}
#pragma mark - Subclass Hooks
- (void)semanticContentAttributeDidChange:(UISemanticContentAttribute)attribute
{
UIUserInterfaceLayoutDirection layoutDirection =
@ -168,8 +186,9 @@
YGNodeRef yogaNode = self.style.yogaNode;
uint32_t childCount = YGNodeGetChildCount(yogaNode);
ASDisplayNodeAssert(childCount == self.yogaChildren.count,
@"Yoga tree should always be in sync with .yogaNodes array! %@", self.yogaChildren);
ASDisplayNodeAssert(childCount == _yogaChildren.count,
@"Yoga tree should always be in sync with .yogaNodes array! %@",
_yogaChildren);
ASLayout *rawSublayouts[childCount];
int i = 0;

View File

@ -49,7 +49,9 @@ void ASDisplayNodePerformBlockOnEveryYogaChild(ASDisplayNode *node, void(^block)
return;
}
block(node);
for (ASDisplayNode *child in [node yogaChildren]) {
// We use the accessor here despite the copy, because the block may modify the yoga tree e.g.
// replacing a node.
for (ASDisplayNode *child in node.yogaChildren) {
ASDisplayNodePerformBlockOnEveryYogaChild(child, block);
}
}