Skip to content
This repository was archived by the owner on Feb 2, 2023. It is now read-only.
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
9 changes: 5 additions & 4 deletions AsyncDisplayKit/Layout/ASBackgroundLayoutSpec.mm
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
#import "ASBaseDefines.h"
#import "ASLayout.h"

static NSString * const kBackgroundChildKey = @"kBackgroundChildKey";
static NSUInteger const kForegroundChildIndex = 0;
static NSUInteger const kBackgroundChildIndex = 1;

@interface ASBackgroundLayoutSpec ()
@end
Expand All @@ -28,7 +29,7 @@ - (instancetype)initWithChild:(id<ASLayoutable>)child background:(id<ASLayoutabl
}

ASDisplayNodeAssertNotNil(child, @"Child cannot be nil");
[self setChild:child];
[self setChild:child forIndex:kForegroundChildIndex];
self.background = background;
return self;
}
Expand Down Expand Up @@ -63,12 +64,12 @@ - (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize

- (void)setBackground:(id<ASLayoutable>)background
{
[super setChild:background forIdentifier:kBackgroundChildKey];
[super setChild:background forIndex:kBackgroundChildIndex];
}

- (id<ASLayoutable>)background
{
return [super childForIdentifier:kBackgroundChildKey];
return [super childForIndex:kBackgroundChildIndex];
}

@end
23 changes: 11 additions & 12 deletions AsyncDisplayKit/Layout/ASLayoutSpec.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,9 @@ NS_ASSUME_NONNULL_BEGIN
* only require a single child.
*
* For layout specs that require a known number of children (ASBackgroundLayoutSpec, for example)
* a subclass should use this method to set the "primary" child. It can then use setChild:forIdentifier:
* to set any other required children. Ideally a subclass would hide this from the user, and use the
* setChild:forIdentifier: internally. For example, ASBackgroundLayoutSpec exposes a backgroundChild
* property that behind the scenes is calling setChild:forIdentifier:.
* a subclass should use this method to set the "primary" child. This is actually the same as calling
* setChild:forIdentifier:0. All other children should be set by defining convenience methods
* that call setChild:forIdentifier behind the scenes.
*/
- (void)setChild:(id<ASLayoutable>)child;

Expand All @@ -52,19 +51,19 @@ NS_ASSUME_NONNULL_BEGIN
*
* @param child A child to be added.
*
* @param identifier An identifier associated with the child.
* @param index An index associated with the child.
*
* @discussion Every ASLayoutSpec must act on at least one child. The ASLayoutSpec base class takes the
* responsibility of holding on to the spec children. Some layout specs, like ASInsetLayoutSpec,
* only require a single child.
*
* For layout specs that require a known number of children (ASBackgroundLayoutSpec, for example)
* a subclass should use the setChild method to set the "primary" child. It can then use this method
* a subclass can use the setChild method to set the "primary" child. It should then use this method
* to set any other required children. Ideally a subclass would hide this from the user, and use the
* setChild:forIdentifier: internally. For example, ASBackgroundLayoutSpec exposes a backgroundChild
* property that behind the scenes is calling setChild:forIdentifier:.
* setChild:forIndex: internally. For example, ASBackgroundLayoutSpec exposes a backgroundChild
* property that behind the scenes is calling setChild:forIndex:.
*/
- (void)setChild:(id<ASLayoutable>)child forIdentifier:(NSString *)identifier;
- (void)setChild:(id<ASLayoutable>)child forIndex:(NSUInteger)index;

/**
* Adds childen to this layout spec.
Expand Down Expand Up @@ -94,11 +93,11 @@ NS_ASSUME_NONNULL_BEGIN
- (nullable id<ASLayoutable>)child;

/**
* Returns the child added to this layout spec using the given identifier.
* Returns the child added to this layout spec using the given index.
*
* @param identifier An identifier associated withe the child.
* @param index An identifier associated withe the child.
*/
- (nullable id<ASLayoutable>)childForIdentifier:(NSString *)identifier;
- (nullable id<ASLayoutable>)childForIndex:(NSUInteger)index;

/**
* Returns all children added to this layout spec.
Expand Down
68 changes: 25 additions & 43 deletions AsyncDisplayKit/Layout/ASLayoutSpec.mm
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,15 @@
#import "ASTraitCollection.h"

#import <objc/runtime.h>
#import <map>
#import <vector>

typedef std::map<unsigned long, id<ASLayoutable>, std::less<unsigned long>> ASChildMap;

@interface ASLayoutSpec() {
ASEnvironmentState _environmentState;
ASDN::RecursiveMutex _propertyLock;

NSArray *_children;
NSMutableDictionary *_childrenWithIdentifier;
ASChildMap _children;
}
@end

Expand All @@ -45,7 +46,6 @@ - (instancetype)init
}
_isMutable = YES;
_environmentState = ASEnvironmentStateMakeDefault();
_children = [NSArray array];
return self;
}

Expand Down Expand Up @@ -102,14 +102,6 @@ - (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize
return child;
}

- (NSMutableDictionary *)childrenWithIdentifier
{
if (!_childrenWithIdentifier) {
_childrenWithIdentifier = [NSMutableDictionary dictionary];
}
return _childrenWithIdentifier;
}

- (void)setParent:(id<ASLayoutable>)parent
{
// FIXME: Locking should be evaluated here. _parent is not widely used yet, though.
Expand All @@ -126,34 +118,23 @@ - (void)setChild:(id<ASLayoutable>)child
if (child) {
id<ASLayoutable> finalLayoutable = [self layoutableToAddFromLayoutable:child];
if (finalLayoutable) {
_children = @[finalLayoutable];
_children[0] = finalLayoutable;
[self propagateUpLayoutable:finalLayoutable];
}
} else {
// remove the only child
_children = [NSArray array];
_children.erase(0);
}
}

- (void)setChild:(id<ASLayoutable>)child forIdentifier:(NSString *)identifier
- (void)setChild:(id<ASLayoutable>)child forIndex:(NSUInteger)index
{
ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable");
if (child) {
id<ASLayoutable> finalLayoutable = [self layoutableToAddFromLayoutable:child];
self.childrenWithIdentifier[identifier] = finalLayoutable;
if (finalLayoutable) {
_children = [_children arrayByAddingObject:finalLayoutable];
}
_children[index] = finalLayoutable;
} else {
id<ASLayoutable> oldChild = self.childrenWithIdentifier[identifier];
if (oldChild) {
self.childrenWithIdentifier[identifier] = nil;
NSMutableArray *mutableChildren = [_children mutableCopy];
[mutableChildren removeObject:oldChild];
_children = [mutableChildren copy];
}
_children.erase(index);
}

// 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];
Expand All @@ -163,32 +144,33 @@ - (void)setChildren:(NSArray<id<ASLayoutable>> *)children
{
ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable");

std::vector<id<ASLayoutable>> finalChildren;
for (id<ASLayoutable> child in children) {
finalChildren.push_back([self layoutableToAddFromLayoutable:child]);
}

_children = nil;
if (finalChildren.size() > 0) {
_children = [NSArray arrayWithObjects:&finalChildren[0] count:finalChildren.size()];
} else {
_children = [NSArray array];
}
_children.clear();
[children enumerateObjectsUsingBlock:^(id<ASLayoutable> _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
_children[idx] = obj;
}];
}

- (id<ASLayoutable>)childForIdentifier:(NSString *)identifier
- (id<ASLayoutable>)childForIndex:(NSUInteger)index
{
return self.childrenWithIdentifier[identifier];
if (index < _children.size()) {
return _children[index];
}
return nil;
}

- (id<ASLayoutable>)child
{
return [_children firstObject];
return _children[0];
}

- (NSArray *)children
{
return _children;
std::vector<ASLayout *> children;
for (ASChildMap::iterator it = _children.begin(); it != _children.end(); ++it ) {
children.push_back(it->second);
}

return [NSArray arrayWithObjects:&children[0] count:children.size()];
}

#pragma mark - ASEnvironment
Expand Down
9 changes: 5 additions & 4 deletions AsyncDisplayKit/Layout/ASOverlayLayoutSpec.mm
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
#import "ASBaseDefines.h"
#import "ASLayout.h"

static NSString * const kOverlayChildKey = @"kOverlayChildKey";
static NSUInteger const kUnderlayChildIndex = 0;
static NSUInteger const kOverlayChildIndex = 1;

@implementation ASOverlayLayoutSpec

Expand All @@ -25,7 +26,7 @@ - (instancetype)initWithChild:(id<ASLayoutable>)child overlay:(id<ASLayoutable>)
}
ASDisplayNodeAssertNotNil(child, @"Child that will be overlayed on shouldn't be nil");
self.overlay = overlay;
[self setChild:child];
[self setChild:child forIndex:kUnderlayChildIndex];
return self;
}

Expand All @@ -36,12 +37,12 @@ + (instancetype)overlayLayoutSpecWithChild:(id<ASLayoutable>)child overlay:(id<A

- (void)setOverlay:(id<ASLayoutable>)overlay
{
[super setChild:overlay forIdentifier:kOverlayChildKey];
[super setChild:overlay forIndex:kOverlayChildIndex];
}

- (id<ASLayoutable>)overlay
{
return [super childForIdentifier:kOverlayChildKey];
return [super childForIndex:kOverlayChildIndex];
}

/**
Expand Down