diff --git a/AsyncDisplayKit/Details/ASEnvironment.h b/AsyncDisplayKit/Details/ASEnvironment.h index 6a42f18cbf..8c473cc08c 100644 --- a/AsyncDisplayKit/Details/ASEnvironment.h +++ b/AsyncDisplayKit/Details/ASEnvironment.h @@ -88,7 +88,7 @@ ASDISPLAYNODE_EXTERN_C_END - (id _Nullable)parent; /// Returns all children of an object which class conforms to the ASEnvironment protocol -- (NSArray> *)children; +- (nullable NSArray> *)children; /// Classes should implement this method and return YES / NO dependent if upward propagation is enabled or not - (BOOL)supportsUpwardPropagation; diff --git a/AsyncDisplayKit/Layout/ASLayoutSpec.h b/AsyncDisplayKit/Layout/ASLayoutSpec.h index dcb9b33246..02a6d4f035 100644 --- a/AsyncDisplayKit/Layout/ASLayoutSpec.h +++ b/AsyncDisplayKit/Layout/ASLayoutSpec.h @@ -25,6 +25,9 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)init; +/** + * Parent of the layout spec + */ @property (nullable, nonatomic, weak) id parent; /** @@ -97,8 +100,10 @@ NS_ASSUME_NONNULL_BEGIN */ - (nullable id)childForIdentifier:(NSString *)identifier; -/** Returns all children added to this layout spec. */ -- (NSArray> *)children; +/** + * Returns all children added to this layout spec. + */ +- (nullable NSArray> *)children; @end diff --git a/AsyncDisplayKit/Layout/ASLayoutSpec.mm b/AsyncDisplayKit/Layout/ASLayoutSpec.mm index 847b491e13..d5830d0c79 100644 --- a/AsyncDisplayKit/Layout/ASLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASLayoutSpec.mm @@ -18,24 +18,23 @@ #import "ASLayout.h" #import "ASThread.h" - #import - -static NSString * const kDefaultChildKey = @"kDefaultChildKey"; -static NSString * const kDefaultChildrenKey = @"kDefaultChildrenKey"; +#import @interface ASLayoutSpec() { ASEnvironmentState _environmentState; ASDN::RecursiveMutex _propertyLock; + + id _child; + NSArray *_children; + NSMutableDictionary *_childrenWithIdentifier; } -@property (nonatomic, strong) NSMutableDictionary *layoutChildren; @end @implementation ASLayoutSpec // these dynamic properties all defined in ASLayoutOptionsPrivate.m @dynamic spacingAfter, spacingBefore, flexGrow, flexShrink, flexBasis, alignSelf, ascender, descender, sizeRange, layoutPosition; -@synthesize layoutChildren = _layoutChildren; @synthesize isFinalLayoutable = _isFinalLayoutable; - (instancetype)init @@ -95,12 +94,12 @@ static NSString * const kDefaultChildrenKey = @"kDefaultChildrenKey"; return child; } -- (NSMutableDictionary *)layoutChildren +- (NSMutableDictionary *)childrenWithIdentifier { - if (!_layoutChildren) { - _layoutChildren = [NSMutableDictionary dictionary]; + if (!_childrenWithIdentifier) { + _childrenWithIdentifier = [NSMutableDictionary dictionary]; } - return _layoutChildren; + return _childrenWithIdentifier; } - (void)setParent:(id)parent @@ -115,46 +114,53 @@ static NSString * const kDefaultChildrenKey = @"kDefaultChildrenKey"; - (void)setChild:(id)child; { - [self setChild:child forIdentifier:kDefaultChildKey]; + ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable"); + + id finalLayoutable = [self layoutableToAddFromLayoutable:child]; + _child = finalLayoutable; + [self propagateUpLayoutable:finalLayoutable]; } - (void)setChild:(id)child forIdentifier:(NSString *)identifier { ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable"); + id finalLayoutable = [self layoutableToAddFromLayoutable:child]; - self.layoutChildren[identifier] = finalLayoutable; - if ([finalLayoutable isKindOfClass:[ASLayoutSpec class]]) { - [(ASLayoutSpec *)finalLayoutable setParent:self]; // This will trigger upward propogation if needed. - } else if ([self supportsUpwardPropagation]) { - ASEnvironmentStatePropagateUp(self, finalLayoutable.environmentState.layoutOptionsState); // Probably an ASDisplayNode - } + self.childrenWithIdentifier[identifier] = finalLayoutable; + + // TODO: Should we propagate up the layoutable at it could happen that multiple children will propagated up their + // layout options and one child will overwrite values from another child + // [self propagateUpLayoutable:finalLayoutable]; } - (void)setChildren:(NSArray *)children { ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable"); - NSMutableArray *finalChildren = [NSMutableArray arrayWithCapacity:children.count]; + std::vector> finalChildren; for (id child in children) { - [finalChildren addObject:[self layoutableToAddFromLayoutable:child]]; + finalChildren.push_back([self layoutableToAddFromLayoutable:child]); } - self.layoutChildren[kDefaultChildrenKey] = [NSArray arrayWithArray:finalChildren]; + _children = nil; + if (finalChildren.size() > 0) { + _children = [NSArray arrayWithObjects:&finalChildren[0] count:finalChildren.size()]; + } } - (id)childForIdentifier:(NSString *)identifier { - return self.layoutChildren[identifier]; + return self.childrenWithIdentifier[identifier]; } - (id)child { - return self.layoutChildren[kDefaultChildKey]; + return _child; } - (NSArray *)children { - return self.layoutChildren[kDefaultChildrenKey]; + return [_children copy]; } @@ -178,6 +184,15 @@ static NSString * const kDefaultChildrenKey = @"kDefaultChildrenKey"; return ASEnvironmentStatePropagationEnabled(); } +- (void)propagateUpLayoutable:(id)layoutable +{ + if ([layoutable isKindOfClass:[ASLayoutSpec class]]) { + [(ASLayoutSpec *)layoutable setParent:self]; // This will trigger upward propogation if needed. + } else if ([self supportsUpwardPropagation]) { + ASEnvironmentStatePropagateUp(self, layoutable.environmentState.layoutOptionsState); // Probably an ASDisplayNode + } +} + ASEnvironmentLayoutOptionsForwarding ASEnvironmentLayoutExtensibilityForwarding