Skip to content
This repository has been archived by the owner on Feb 2, 2023. It is now read-only.

[ASTraitCollection] Remove traitCollectionContext from ASTraitCollection; add containerWindowSize #1860

Merged
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
12 changes: 0 additions & 12 deletions AsyncDisplayKit/ASViewController.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,6 @@ typedef ASTraitCollection * _Nonnull (^ASDisplayTraitsForTraitWindowSizeBlock)(C

@property (nonatomic, strong, readonly) DisplayNodeType node;

/**
* An optional context to pass along with an ASTraitCollection.
* This can be used to pass any internal state to all subnodes via the ASTraitCollection that is not
* included in UITraitCollection. This could range from more fine-tuned size classes to a class of
* constants that is based upon the new trait collection.
*
* Be aware that internally this context is held by a C struct which cannot retain the pointer. Therefore
* ASVC keeps a strong reference to the context to make sure that it stays alive. If you change this value
* it will propagate the change to the subnodes.
*/
@property (nonatomic, strong) id _Nullable traitCollectionContext;

/**
* Set this block to customize the ASDisplayTraits returned when the VC transitions to the given traitCollection.
*/
Expand Down
40 changes: 7 additions & 33 deletions AsyncDisplayKit/ASViewController.mm
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,6 @@ - (instancetype)initWithNode:(ASDisplayNode *)node
return self;
}

- (void)dealloc
{
if (_traitCollectionContext != nil) {
// The setter will iterate through the VC's subnodes and replace the traitCollectionContext in their ASEnvironmentTraitCollection with nil.
// Since the VC holds the only strong reference to this context and we are in the process of destroying
// the VC, all the references in the subnodes will be unsafe unless we nil them out. More than likely all the subnodes will be dealloc'ed
// as part of the VC being dealloc'ed, but this is just to make extra sure.
self.traitCollectionContext = nil;
}
}

- (void)loadView
{
ASDisplayNodeAssertTrue(!_node.layerBacked);
Expand Down Expand Up @@ -199,37 +188,26 @@ - (ASInterfaceState)interfaceState

#pragma mark - ASEnvironmentTraitCollection

- (void)setTraitCollectionContext:(id)traitCollectionContext
{
if (_traitCollectionContext != traitCollectionContext) {
// nil out the displayContext in the subnodes so they aren't hanging around with a dealloc'ed pointer don't set
// the new context yet as this will cause ASEnvironmentTraitCollectionIsEqualToASEnvironmentTraitCollection to fail
ASEnvironmentTraitCollectionUpdateDisplayContext(self.node, nil);

_traitCollectionContext = traitCollectionContext;
}
}

- (ASEnvironmentTraitCollection)environmentTraitCollectionForUITraitCollection:(UITraitCollection *)traitCollection
{
if (self.overrideDisplayTraitsWithTraitCollection) {
ASTraitCollection *asyncTraitCollection = self.overrideDisplayTraitsWithTraitCollection(traitCollection);
self.traitCollectionContext = asyncTraitCollection.traitCollectionContext;
return [asyncTraitCollection environmentTraitCollection];
}

ASDisplayNodeAssertMainThread();
ASEnvironmentTraitCollection asyncTraitCollection = ASEnvironmentTraitCollectionFromUITraitCollection(traitCollection);
asyncTraitCollection.displayContext = self.traitCollectionContext;
asyncTraitCollection.containerSize = self.view.frame.size;
return asyncTraitCollection;
}

- (ASEnvironmentTraitCollection)environmentTraitCollectionForWindowSize:(CGSize)windowSize
{
if (self.overrideDisplayTraitsWithWindowSize) {
ASTraitCollection *traitCollection = self.overrideDisplayTraitsWithWindowSize(windowSize);
self.traitCollectionContext = traitCollection.traitCollectionContext;
return [traitCollection environmentTraitCollection];
}
self.node.environmentTraitCollection.containerSize = windowSize;
return self.node.environmentTraitCollection;
}

Expand All @@ -255,17 +233,13 @@ - (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection
[super traitCollectionDidChange:previousTraitCollection];

ASEnvironmentTraitCollection environmentTraitCollection = [self environmentTraitCollectionForUITraitCollection:self.traitCollection];
environmentTraitCollection.containerSize = self.view.bounds.size;
[self progagateNewEnvironmentTraitCollection:environmentTraitCollection];
}

- (void)willTransitionToTraitCollection:(UITraitCollection *)newCollection withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
[super willTransitionToTraitCollection:newCollection withTransitionCoordinator:coordinator];

ASEnvironmentTraitCollection environmentTraitCollection = [self environmentTraitCollectionForUITraitCollection:newCollection];
[self progagateNewEnvironmentTraitCollection:environmentTraitCollection];
}

// Note: We don't override willTransitionToTraitCollection:withTransitionCoordinator: because viewWillTransitionToSize:withTransitionCoordinator: will also called
// called in all these cases. However, there are cases where viewWillTransitionToSize:withTransitionCoordinator: but willTransitionToTraitCollection:withTransitionCoordinator:
// is not.
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
Expand Down
25 changes: 3 additions & 22 deletions AsyncDisplayKit/Details/ASEnvironment.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,25 +69,9 @@ typedef struct ASEnvironmentTraitCollection {
UIUserInterfaceIdiom userInterfaceIdiom;
UIUserInterfaceSizeClass verticalSizeClass;
UIForceTouchCapability forceTouchCapability;

// WARNING:
// This pointer is in a C struct and therefore not managed by ARC. It is
// an unsafe unretained pointer, so when you dereference it you better be
// sure that it is valid.
//
// Use displayContext when you wish to pass view context specific data along with the
// display traits to subnodes. This should be a piece of data owned by an
// ASViewController, which will ensure that the data is still valid when laying out
// its subviews. When the VC is dealloc'ed, the displayContext it created will also
// be dealloced but any subnodes that are hanging around (why would they be?) will now
// have a displayContext that points to a bad pointer.
//
// As an added precaution ASDisplayTraitsClearDisplayContext is called from ASVC's desctructor
// which will propagate a nil displayContext to its subnodes.
id __unsafe_unretained displayContext;
} ASEnvironmentTraitCollection;

extern void ASEnvironmentTraitCollectionUpdateDisplayContext(id<ASEnvironment> rootEnvironment, id _Nullable context);
CGSize containerSize;
} ASEnvironmentTraitCollection;

extern ASEnvironmentTraitCollection ASEnvironmentTraitCollectionFromUITraitCollection(UITraitCollection *traitCollection);
extern BOOL ASEnvironmentTraitCollectionIsEqualToASEnvironmentTraitCollection(ASEnvironmentTraitCollection lhs, ASEnvironmentTraitCollection rhs);
Expand Down Expand Up @@ -165,14 +149,11 @@ ASDISPLAYNODE_EXTERN_C_END
if (ASEnvironmentTraitCollectionIsEqualToASEnvironmentTraitCollection(currentTraits, oldTraits) == NO) {\
/* Must dispatch to main for self.view && [self.view.dataController completedNodes]*/ \
ASPerformBlockOnMainThread(^{\
BOOL needsLayout = (oldTraits.displayContext == currentTraits.displayContext) || currentTraits.displayContext != nil;\
NSArray<NSArray <ASCellNode *> *> *completedNodes = [self.view.dataController completedNodes];\
for (NSArray *sectionArray in completedNodes) {\
for (ASCellNode *cellNode in sectionArray) {\
ASEnvironmentStatePropagateDown(cellNode, currentTraits);\
if (needsLayout) {\
[cellNode setNeedsLayout];\
}\
[cellNode setNeedsLayout];\
}\
}\
});\
Expand Down
16 changes: 2 additions & 14 deletions AsyncDisplayKit/Details/ASEnvironment.mm
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,11 @@ ASEnvironmentHierarchyState _ASEnvironmentHierarchyStateMakeDefault()
};
}

extern void ASEnvironmentTraitCollectionUpdateDisplayContext(id<ASEnvironment> rootEnvironment, id context)
{
ASEnvironmentState envState = [rootEnvironment environmentState];
ASEnvironmentTraitCollection environmentTraitCollection = envState.environmentTraitCollection;
environmentTraitCollection.displayContext = context;
envState.environmentTraitCollection = environmentTraitCollection;
[rootEnvironment setEnvironmentState:envState];

for (id<ASEnvironment> child in [rootEnvironment children]) {
ASEnvironmentStatePropagateDown(child, environmentTraitCollection);
}
}

ASEnvironmentTraitCollection _ASEnvironmentTraitCollectionMakeDefault()
{
return (ASEnvironmentTraitCollection) {
// Default values can be defined in here
.containerSize = CGSizeZero,
};
}

Expand All @@ -69,7 +57,7 @@ BOOL ASEnvironmentTraitCollectionIsEqualToASEnvironmentTraitCollection(ASEnviron
lhs.displayScale == rhs.displayScale &&
lhs.userInterfaceIdiom == rhs.userInterfaceIdiom &&
lhs.forceTouchCapability == rhs.forceTouchCapability &&
lhs.displayContext == rhs.displayContext;
CGSizeEqualToSize(lhs.containerSize, rhs.containerSize);
}

ASEnvironmentState ASEnvironmentStateMakeDefault()
Expand Down
20 changes: 3 additions & 17 deletions AsyncDisplayKit/Details/ASTraitCollection.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,35 +18,21 @@
@property (nonatomic, assign, readonly) UIUserInterfaceIdiom userInterfaceIdiom;
@property (nonatomic, assign, readonly) UIUserInterfaceSizeClass verticalSizeClass;
@property (nonatomic, assign, readonly) UIForceTouchCapability forceTouchCapability;

/**
* An optional context to pass along with an ASTraitCollection.
* This can be used to pass any internal state to all subnodes via the ASTraitCollection that is not
* included in UITraitCollection. This could range from more fine-tuned size classes to a class of
* constants that is based upon the new trait collection.
*
* Be aware that internally this context is held by a C struct which cannot retain the pointer.
* ASTraitCollection is generally a very short-lived class, existing only to provide a non-struct API
* to trait collections. When an ASTraitCollection is returned via one of ASViewController's 2
* custom trait collection creation blocks, traitCollectionContext is assigned to the VC's traitCollectionContext.
* This makes sure that the VC is the owner of the context and ASEnvironmentTraitCollections will not
* have a reference to a dangling pointer.
*/
@property (nonatomic, strong, readonly) id traitCollectionContext;
@property (nonatomic, assign, readonly) CGSize containerSize;


+ (ASTraitCollection *)traitCollectionWithASEnvironmentTraitCollection:(ASEnvironmentTraitCollection)traits;

+ (ASTraitCollection *)traitCollectionWithUITraitCollection:(UITraitCollection *)traitCollection
traitCollectionContext:(id)traitCollectionContext;
containerSize:(CGSize)windowSize;


+ (ASTraitCollection *)traitCollectionWithDisplayScale:(CGFloat)displayScale
userInterfaceIdiom:(UIUserInterfaceIdiom)userInterfaceIdiom
horizontalSizeClass:(UIUserInterfaceSizeClass)horizontalSizeClass
verticalSizeClass:(UIUserInterfaceSizeClass)verticalSizeClass
forceTouchCapability:(UIForceTouchCapability)forceTouchCapability
traitCollectionContext:(id)traitCollectionContext;
containerSize:(CGSize)windowSize;


- (ASEnvironmentTraitCollection)environmentTraitCollection;
Expand Down
30 changes: 15 additions & 15 deletions AsyncDisplayKit/Details/ASTraitCollection.m
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ - (instancetype)initWithDisplayScale:(CGFloat)displayScale
horizontalSizeClass:(UIUserInterfaceSizeClass)horizontalSizeClass
verticalSizeClass:(UIUserInterfaceSizeClass)verticalSizeClass
forceTouchCapability:(UIForceTouchCapability)forceTouchCapability
traitCollectionContext:(id)traitCollectionContext
containerSize:(CGSize)windowSize
{
self = [super init];
if (self) {
Expand All @@ -30,7 +30,7 @@ - (instancetype)initWithDisplayScale:(CGFloat)displayScale
_horizontalSizeClass = horizontalSizeClass;
_verticalSizeClass = verticalSizeClass;
_forceTouchCapability = forceTouchCapability;
_traitCollectionContext = traitCollectionContext;
_containerSize = windowSize;
}
return self;
}
Expand All @@ -40,29 +40,29 @@ + (ASTraitCollection *)traitCollectionWithDisplayScale:(CGFloat)displayScale
horizontalSizeClass:(UIUserInterfaceSizeClass)horizontalSizeClass
verticalSizeClass:(UIUserInterfaceSizeClass)verticalSizeClass
forceTouchCapability:(UIForceTouchCapability)forceTouchCapability
traitCollectionContext:(id)traitCollectionContext
containerSize:(CGSize)windowSize
{
return [[[self class] alloc] initWithDisplayScale:displayScale
userInterfaceIdiom:userInterfaceIdiom
horizontalSizeClass:horizontalSizeClass
verticalSizeClass:verticalSizeClass
forceTouchCapability:forceTouchCapability
traitCollectionContext:traitCollectionContext];
containerSize:windowSize];
}

+ (ASTraitCollection *)traitCollectionWithASEnvironmentTraitCollection:(ASEnvironmentTraitCollection)traits
{
return [[[self class] alloc] initWithDisplayScale:traits.displayScale
userInterfaceIdiom:traits.userInterfaceIdiom
horizontalSizeClass:traits.horizontalSizeClass
verticalSizeClass:traits.verticalSizeClass
forceTouchCapability:traits.forceTouchCapability
traitCollectionContext:traits.displayContext];
return [[[self class] alloc] initWithDisplayScale:traits.displayScale
userInterfaceIdiom:traits.userInterfaceIdiom
horizontalSizeClass:traits.horizontalSizeClass
verticalSizeClass:traits.verticalSizeClass
forceTouchCapability:traits.forceTouchCapability
containerSize:traits.containerSize];

}

+ (ASTraitCollection *)traitCollectionWithUITraitCollection:(UITraitCollection *)traitCollection
traitCollectionContext:(id)traitCollectionContext
containerSize:(CGSize)windowSize
{
ASTraitCollection *asyncTraitCollection = nil;
if (AS_AT_LEAST_IOS9) {
Expand All @@ -71,15 +71,15 @@ + (ASTraitCollection *)traitCollectionWithUITraitCollection:(UITraitCollection *
horizontalSizeClass:traitCollection.horizontalSizeClass
verticalSizeClass:traitCollection.verticalSizeClass
forceTouchCapability:traitCollection.forceTouchCapability
traitCollectionContext:traitCollectionContext];
containerSize:windowSize];
}
else if (AS_AT_LEAST_IOS8) {
asyncTraitCollection = [[[self class] alloc] initWithDisplayScale:traitCollection.displayScale
userInterfaceIdiom:traitCollection.userInterfaceIdiom
horizontalSizeClass:traitCollection.horizontalSizeClass
verticalSizeClass:traitCollection.verticalSizeClass
forceTouchCapability:0
traitCollectionContext:traitCollectionContext];
containerSize:windowSize];
} else {
asyncTraitCollection = [[[self class] alloc] init];
}
Expand All @@ -95,7 +95,7 @@ - (ASEnvironmentTraitCollection)environmentTraitCollection
.userInterfaceIdiom = self.userInterfaceIdiom,
.verticalSizeClass = self.verticalSizeClass,
.forceTouchCapability = self.forceTouchCapability,
.displayContext = self.traitCollectionContext,
.containerSize = self.containerSize,
};
}

Expand All @@ -105,7 +105,7 @@ - (BOOL)isEqualToTraitCollection:(ASTraitCollection *)traitCollection
self.horizontalSizeClass == traitCollection.horizontalSizeClass &&
self.verticalSizeClass == traitCollection.verticalSizeClass &&
self.userInterfaceIdiom == traitCollection.userInterfaceIdiom &&
self.traitCollectionContext == traitCollection.traitCollectionContext &&
CGSizeEqualToSize(self.containerSize, traitCollection.containerSize) &&
self.forceTouchCapability == traitCollection.forceTouchCapability;
}

Expand Down
2 changes: 1 addition & 1 deletion AsyncDisplayKit/Private/ASEnvironmentInternal.mm
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ ASEnvironmentState ASEnvironmentMergeObjectAndState(ASEnvironmentState childEnvi
childTraitCollection.userInterfaceIdiom = parentTraitCollection.userInterfaceIdiom;
childTraitCollection.forceTouchCapability = parentTraitCollection.forceTouchCapability;
childTraitCollection.displayScale = parentTraitCollection.displayScale;
childTraitCollection.displayContext = parentTraitCollection.displayContext;
childTraitCollection.containerSize = parentTraitCollection.containerSize;
childEnvironmentState.environmentTraitCollection = childTraitCollection;

}
Expand Down