From 4b54144f556ab9d5692b67759c3d546b2a27a068 Mon Sep 17 00:00:00 2001 From: rcancro Date: Wed, 11 May 2016 10:21:11 -0700 Subject: [PATCH] Levi's comments --- AsyncDisplayKit/ASDisplayNode.mm | 7 +- AsyncDisplayKit/ASViewController.h | 12 ++- AsyncDisplayKit/ASViewController.mm | 26 +++-- AsyncDisplayKit/Details/ASDataController.mm | 2 +- AsyncDisplayKit/Details/ASEnvironment.h | 8 +- AsyncDisplayKit/Details/ASEnvironment.mm | 18 ++-- AsyncDisplayKit/Details/ASTraitCollection.h | 41 +++++-- AsyncDisplayKit/Details/ASTraitCollection.m | 101 ++++++++++-------- AsyncDisplayKit/Layout/ASLayoutSpec.mm | 7 +- .../Private/ASDisplayNodeInternal.h | 6 ++ .../ASTraitCollection/Sample/KittenNode.m | 9 +- 11 files changed, 156 insertions(+), 81 deletions(-) diff --git a/AsyncDisplayKit/ASDisplayNode.mm b/AsyncDisplayKit/ASDisplayNode.mm index 2e04ba499c..ead40263d4 100644 --- a/AsyncDisplayKit/ASDisplayNode.mm +++ b/AsyncDisplayKit/ASDisplayNode.mm @@ -2718,13 +2718,18 @@ static const char *ASDisplayNodeDrawingPriorityKey = "ASDrawingPriority"; return ASEnvironmentStateTraitCollectionPropagationEnabled(); } +- (ASEnvironmentTraitCollection)environmentTraitCollection +{ + return _environmentState.traitCollection; +} + ASEnvironmentLayoutOptionsForwarding ASEnvironmentLayoutExtensibilityForwarding - (ASTraitCollection *)asyncTraitCollection { ASDN::MutexLocker l(_propertyLock); - return [ASTraitCollection displayTraitsWithASEnvironmentTraitCollection:_environmentState.traitCollection]; + return [ASTraitCollection traitCollectionWithASEnvironmentTraitCollection:_environmentState.traitCollection]; } #if TARGET_OS_TV diff --git a/AsyncDisplayKit/ASViewController.h b/AsyncDisplayKit/ASViewController.h index 1796cbc459..4102ee80ba 100644 --- a/AsyncDisplayKit/ASViewController.h +++ b/AsyncDisplayKit/ASViewController.h @@ -22,7 +22,17 @@ typedef ASTraitCollection * _Nonnull (^ASDisplayTraitsForTraitWindowSizeBlock)(C @property (nonatomic, strong, readonly) DisplayNodeType node; -@property (nonatomic, strong) id displayTraitsContext; +/** + * 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 traitColectionContext; /** * Set this block to customize the ASDisplayTraits returned when the VC transitions to the given traitCollection. diff --git a/AsyncDisplayKit/ASViewController.mm b/AsyncDisplayKit/ASViewController.mm index b902a1ec7e..f90f34a180 100644 --- a/AsyncDisplayKit/ASViewController.mm +++ b/AsyncDisplayKit/ASViewController.mm @@ -9,6 +9,7 @@ #import "ASViewController.h" #import "ASAssert.h" #import "ASDimension.h" +#import "ASDisplayNodeInternal.h" #import "ASDisplayNode+FrameworkPrivate.h" #import "ASDisplayNode+Beta.h" #import "ASTraitCollection.h" @@ -50,9 +51,8 @@ - (void)dealloc { - if (_displayTraitsContext != nil) { - ASEnvironmentTraitCollectionClearDisplayContext(self.node); - _displayTraitsContext = nil; + if (_traitColectionContext != nil) { + self.traitColectionContext = nil; } } @@ -144,16 +144,26 @@ #pragma mark - ASEnvironmentTraitCollection +- (void)setTraitColectionContext:(id)traitColectionContext +{ + if (_traitColectionContext != traitColectionContext) { + // propagate first so that nodes aren't hanging around with a dealloc'ed pointer + ASEnvironmentTraitCollectionUpdateDisplayContext(self.node, traitColectionContext); + + _traitColectionContext = traitColectionContext; + } +} + - (ASEnvironmentTraitCollection)displayTraitsForTraitCollection:(UITraitCollection *)traitCollection { if (self.overrideDisplayTraitsWithTraitCollection) { ASTraitCollection *asyncTraitCollection = self.overrideDisplayTraitsWithTraitCollection(traitCollection); - asyncTraitCollection.isMutable = NO; + self.traitColectionContext = asyncTraitCollection.traitColectionContext; return [asyncTraitCollection environmentTraitCollection]; } ASEnvironmentTraitCollection asyncTraitCollection = ASEnvironmentTraitCollectionFromUITraitCollection(traitCollection); - asyncTraitCollection.displayContext = _displayTraitsContext; + asyncTraitCollection.displayContext = self.traitColectionContext; return asyncTraitCollection; } @@ -161,10 +171,10 @@ { if (self.overrideDisplayTraitsWithWindowSize) { ASTraitCollection *traitCollection = self.overrideDisplayTraitsWithWindowSize(windowSize); - traitCollection.isMutable = NO; + self.traitColectionContext = traitCollection.traitColectionContext; return [traitCollection environmentTraitCollection]; } - return self.node.environmentState.traitCollection; + return self.node.environmentTraitCollection; } - (void)progagateNewDisplayTraits:(ASEnvironmentTraitCollection)traitCollection @@ -174,7 +184,7 @@ if (ASEnvironmentTraitCollectionIsEqualToASEnvironmentTraitCollection(traitCollection, oldTraitCollection) == NO) { environmentState.traitCollection = traitCollection; - [self.node setEnvironmentState:environmentState]; + self.node.environmentState = environmentState; [self.node setNeedsLayout]; NSArray> *children = [self.node children]; diff --git a/AsyncDisplayKit/Details/ASDataController.mm b/AsyncDisplayKit/Details/ASDataController.mm index ad049cb187..3271ebb55e 100644 --- a/AsyncDisplayKit/Details/ASDataController.mm +++ b/AsyncDisplayKit/Details/ASDataController.mm @@ -525,7 +525,7 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; ASCellNodeBlock nodeBlockPropagatingDisplayTraits = ^{ ASCellNode *cellNode = nodeBlock(); id environment = [self.environmentDelegate dataControllerEnvironment]; - ASEnvironmentStatePropagateDown(cellNode, [environment environmentState].traitCollection); + ASEnvironmentStatePropagateDown(cellNode, [environment environmentTraitCollection]); return cellNode; }; diff --git a/AsyncDisplayKit/Details/ASEnvironment.h b/AsyncDisplayKit/Details/ASEnvironment.h index 99a0a3838b..580c4a64d3 100644 --- a/AsyncDisplayKit/Details/ASEnvironment.h +++ b/AsyncDisplayKit/Details/ASEnvironment.h @@ -87,10 +87,10 @@ typedef struct ASEnvironmentTraitCollection { id __unsafe_unretained displayContext; } ASEnvironmentTraitCollection; -extern void ASEnvironmentTraitCollectionClearDisplayContext(id rootEnvironment); +extern void ASEnvironmentTraitCollectionUpdateDisplayContext(id rootEnvironment, id _Nullable context); extern ASEnvironmentTraitCollection ASEnvironmentTraitCollectionFromUITraitCollection(UITraitCollection *traitCollection); -extern BOOL ASEnvironmentTraitCollectionIsEqualToASEnvironmentTraitCollection(ASEnvironmentTraitCollection displayTraits0, ASEnvironmentTraitCollection displayTraits1); +extern BOOL ASEnvironmentTraitCollectionIsEqualToASEnvironmentTraitCollection(ASEnvironmentTraitCollection lhs, ASEnvironmentTraitCollection rhs); #pragma mark - ASEnvironmentState @@ -133,6 +133,10 @@ ASDISPLAYNODE_EXTERN_C_END /// Returns an NSObject-representation of the environment's ASEnvironmentDisplayTraits - (ASTraitCollection *)asyncTraitCollection; +/// Returns a struct-representation of the environment's ASEnvironmentDisplayTraits. This only exists as a internal +/// convenience method. Users should access the trait collections through the NSObject based asyncTraitCollection API +- (ASEnvironmentTraitCollection)environmentTraitCollection; + @end // ASCollection/TableNodes don't actually have ASCellNodes as subnodes. Because of this we can't rely on display trait diff --git a/AsyncDisplayKit/Details/ASEnvironment.mm b/AsyncDisplayKit/Details/ASEnvironment.mm index af6ee24f98..b1e17e95fa 100644 --- a/AsyncDisplayKit/Details/ASEnvironment.mm +++ b/AsyncDisplayKit/Details/ASEnvironment.mm @@ -26,11 +26,11 @@ ASEnvironmentHierarchyState _ASEnvironmentHierarchyStateMakeDefault() }; } -extern void ASEnvironmentTraitCollectionClearDisplayContext(id rootEnvironment) +extern void ASEnvironmentTraitCollectionUpdateDisplayContext(id rootEnvironment, id context) { ASEnvironmentState envState = [rootEnvironment environmentState]; ASEnvironmentTraitCollection displayTraits = envState.traitCollection; - displayTraits.displayContext = nil; + displayTraits.displayContext = context; envState.traitCollection = displayTraits; [rootEnvironment setEnvironmentState:envState]; @@ -61,15 +61,15 @@ ASEnvironmentTraitCollection ASEnvironmentTraitCollectionFromUITraitCollection(U return asyncTraitCollection; } -BOOL ASEnvironmentTraitCollectionIsEqualToASEnvironmentTraitCollection(ASEnvironmentTraitCollection traitCollection0, ASEnvironmentTraitCollection traitCollection1) +BOOL ASEnvironmentTraitCollectionIsEqualToASEnvironmentTraitCollection(ASEnvironmentTraitCollection lhs, ASEnvironmentTraitCollection rhs) { return - traitCollection0.verticalSizeClass == traitCollection1.verticalSizeClass && - traitCollection0.horizontalSizeClass == traitCollection1.horizontalSizeClass && - traitCollection0.displayScale == traitCollection1.displayScale && - traitCollection0.userInterfaceIdiom == traitCollection1.userInterfaceIdiom && - traitCollection0.forceTouchCapability == traitCollection1.forceTouchCapability && - traitCollection0.displayContext == traitCollection1.displayContext; + lhs.verticalSizeClass == rhs.verticalSizeClass && + lhs.horizontalSizeClass == rhs.horizontalSizeClass && + lhs.displayScale == rhs.displayScale && + lhs.userInterfaceIdiom == rhs.userInterfaceIdiom && + lhs.forceTouchCapability == rhs.forceTouchCapability && + lhs.displayContext == rhs.displayContext; } ASEnvironmentState ASEnvironmentStateMakeDefault() diff --git a/AsyncDisplayKit/Details/ASTraitCollection.h b/AsyncDisplayKit/Details/ASTraitCollection.h index 32f65cab89..0367e2fcd9 100644 --- a/AsyncDisplayKit/Details/ASTraitCollection.h +++ b/AsyncDisplayKit/Details/ASTraitCollection.h @@ -13,16 +13,41 @@ @interface ASTraitCollection : NSObject -@property (nonatomic, assign) BOOL isMutable; +@property (nonatomic, assign, readonly) CGFloat displayScale; +@property (nonatomic, assign, readonly) UIUserInterfaceSizeClass horizontalSizeClass; +@property (nonatomic, assign, readonly) UIUserInterfaceIdiom userInterfaceIdiom; +@property (nonatomic, assign, readonly) UIUserInterfaceSizeClass verticalSizeClass; +@property (nonatomic, assign, readonly) UIForceTouchCapability forceTouchCapability; -@property (nonatomic, assign) CGFloat displayScale; -@property (nonatomic, assign) UIUserInterfaceSizeClass horizontalSizeClass; -@property (nonatomic, assign) UIUserInterfaceIdiom userInterfaceIdiom; -@property (nonatomic, assign) UIUserInterfaceSizeClass verticalSizeClass; -@property (nonatomic, assign) 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, traitColectionContext is assigned to the VC's traitColectionContext. + * 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 traitColectionContext; + + ++ (ASTraitCollection *)traitCollectionWithASEnvironmentTraitCollection:(ASEnvironmentTraitCollection)traits; + ++ (ASTraitCollection *)traitCollectionWithUITraitCollection:(UITraitCollection *)traitCollection + traitCollectionContext:(id)traitCollectionContext; + + ++ (ASTraitCollection *)traitCollectionWithDisplayScale:(CGFloat)displayScale + userInterfaceIdiom:(UIUserInterfaceIdiom)userInterfaceIdiom + horizontalSizeClass:(UIUserInterfaceSizeClass)horizontalSizeClass + verticalSizeClass:(UIUserInterfaceSizeClass)verticalSizeClass + forceTouchCapability:(UIForceTouchCapability)forceTouchCapability + traitCollectionContext:(id)traitCollectionContext; -+ (ASTraitCollection *)displayTraitsWithASEnvironmentTraitCollection:(ASEnvironmentTraitCollection)traits; -+ (ASTraitCollection *)displayTraitsWithUITraitCollection:(UITraitCollection *)traitCollection; - (ASEnvironmentTraitCollection)environmentTraitCollection; diff --git a/AsyncDisplayKit/Details/ASTraitCollection.m b/AsyncDisplayKit/Details/ASTraitCollection.m index f13a43a50b..9e41d2b273 100644 --- a/AsyncDisplayKit/Details/ASTraitCollection.m +++ b/AsyncDisplayKit/Details/ASTraitCollection.m @@ -12,68 +12,74 @@ @implementation ASTraitCollection -- (instancetype)init +- (instancetype)initWithDisplayScale:(CGFloat)displayScale + userInterfaceIdiom:(UIUserInterfaceIdiom)userInterfaceIdiom + horizontalSizeClass:(UIUserInterfaceSizeClass)horizontalSizeClass + verticalSizeClass:(UIUserInterfaceSizeClass)verticalSizeClass + forceTouchCapability:(UIForceTouchCapability)forceTouchCapability + traitCollectionContext:(id)traitCollectionContext { self = [super init]; if (self) { - _isMutable = YES; + _displayScale = displayScale; + _userInterfaceIdiom = userInterfaceIdiom; + _horizontalSizeClass = horizontalSizeClass; + _verticalSizeClass = verticalSizeClass; + _forceTouchCapability = forceTouchCapability; + _traitColectionContext = traitCollectionContext; } return self; } -- (void)setDisplayScale:(CGFloat)displayScale ++ (ASTraitCollection *)traitCollectionWithDisplayScale:(CGFloat)displayScale + userInterfaceIdiom:(UIUserInterfaceIdiom)userInterfaceIdiom + horizontalSizeClass:(UIUserInterfaceSizeClass)horizontalSizeClass + verticalSizeClass:(UIUserInterfaceSizeClass)verticalSizeClass + forceTouchCapability:(UIForceTouchCapability)forceTouchCapability + traitCollectionContext:(id)traitCollectionContext { - ASDisplayNodeAssert(self.isMutable, @"ASDisplayTraits is no longer mutable"); - _displayScale = displayScale; + return [[[self class] alloc] initWithDisplayScale:displayScale + userInterfaceIdiom:userInterfaceIdiom + horizontalSizeClass:horizontalSizeClass + verticalSizeClass:verticalSizeClass + forceTouchCapability:forceTouchCapability + traitCollectionContext:traitCollectionContext]; } -- (void)setHorizontalSizeClass:(UIUserInterfaceSizeClass)horizontalSizeClass ++ (ASTraitCollection *)traitCollectionWithASEnvironmentTraitCollection:(ASEnvironmentTraitCollection)traits { - ASDisplayNodeAssert(self.isMutable, @"ASDisplayTraits is no longer mutable"); - _horizontalSizeClass = horizontalSizeClass; + return [[[self class] alloc] initWithDisplayScale:traits.displayScale + userInterfaceIdiom:traits.userInterfaceIdiom + horizontalSizeClass:traits.horizontalSizeClass + verticalSizeClass:traits.verticalSizeClass + forceTouchCapability:traits.forceTouchCapability + traitCollectionContext:traits.displayContext]; + } -- (void)setUserInterfaceIdiom:(UIUserInterfaceIdiom)userInterfaceIdiom ++ (ASTraitCollection *)traitCollectionWithUITraitCollection:(UITraitCollection *)traitCollection + traitCollectionContext:(id)traitCollectionContext { - ASDisplayNodeAssert(self.isMutable, @"ASDisplayTraits is no longer mutable"); - _userInterfaceIdiom = userInterfaceIdiom; -} - -- (void)setVerticalSizeClass:(UIUserInterfaceSizeClass)verticalSizeClass -{ - ASDisplayNodeAssert(self.isMutable, @"ASDisplayTraits is no longer mutable"); - _verticalSizeClass = verticalSizeClass; -} - -- (void)setForceTouchCapability:(UIForceTouchCapability)forceTouchCapability -{ - ASDisplayNodeAssert(self.isMutable, @"ASDisplayTraits is no longer mutable"); - _forceTouchCapability = forceTouchCapability; -} - -+ (ASTraitCollection *)displayTraitsWithASEnvironmentTraitCollection:(ASEnvironmentTraitCollection)traits -{ - ASTraitCollection *traitCollection = [[ASTraitCollection alloc] init]; - traitCollection.displayScale = traits.displayScale; - traitCollection.horizontalSizeClass = traits.horizontalSizeClass; - traitCollection.verticalSizeClass = traits.verticalSizeClass; - traitCollection.userInterfaceIdiom = traits.userInterfaceIdiom; - traitCollection.forceTouchCapability = traits.forceTouchCapability; - return traitCollection; -} - -+ (ASTraitCollection *)displayTraitsWithUITraitCollection:(UITraitCollection *)traitCollection -{ - ASTraitCollection *asyncTraitCollection = [[ASTraitCollection alloc] init]; - if (AS_AT_LEAST_IOS8) { - asyncTraitCollection.displayScale = traitCollection.displayScale; - asyncTraitCollection.horizontalSizeClass = traitCollection.horizontalSizeClass; - asyncTraitCollection.verticalSizeClass = traitCollection.verticalSizeClass; - asyncTraitCollection.userInterfaceIdiom = traitCollection.userInterfaceIdiom; - if (AS_AT_LEAST_IOS9) { - asyncTraitCollection.forceTouchCapability = traitCollection.forceTouchCapability; - } + ASTraitCollection *asyncTraitCollection = nil; + if (AS_AT_LEAST_IOS9) { + asyncTraitCollection = [[[self class] alloc] initWithDisplayScale:traitCollection.displayScale + userInterfaceIdiom:traitCollection.userInterfaceIdiom + horizontalSizeClass:traitCollection.horizontalSizeClass + verticalSizeClass:traitCollection.verticalSizeClass + forceTouchCapability:traitCollection.forceTouchCapability + traitCollectionContext:traitCollectionContext]; } + 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]; + } else { + asyncTraitCollection = [[[self class] alloc] init]; + } + return asyncTraitCollection; } @@ -85,6 +91,7 @@ .userInterfaceIdiom = self.userInterfaceIdiom, .verticalSizeClass = self.verticalSizeClass, .forceTouchCapability = self.forceTouchCapability, + .displayContext = self.traitColectionContext, }; } diff --git a/AsyncDisplayKit/Layout/ASLayoutSpec.mm b/AsyncDisplayKit/Layout/ASLayoutSpec.mm index 0401c1f0f9..7d8995978b 100644 --- a/AsyncDisplayKit/Layout/ASLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASLayoutSpec.mm @@ -201,13 +201,18 @@ } } +- (ASEnvironmentTraitCollection)environmentTraitCollection +{ + return _environmentState.traitCollection; +} + ASEnvironmentLayoutOptionsForwarding ASEnvironmentLayoutExtensibilityForwarding - (ASTraitCollection *)asyncTraitCollection { ASDN::MutexLocker l(_propertyLock); - return [ASTraitCollection displayTraitsWithASEnvironmentTraitCollection:_environmentState.traitCollection]; + return [ASTraitCollection traitCollectionWithASEnvironmentTraitCollection:_environmentState.traitCollection]; } @end diff --git a/AsyncDisplayKit/Private/ASDisplayNodeInternal.h b/AsyncDisplayKit/Private/ASDisplayNodeInternal.h index ca11a8746a..f8de80ce3f 100644 --- a/AsyncDisplayKit/Private/ASDisplayNodeInternal.h +++ b/AsyncDisplayKit/Private/ASDisplayNodeInternal.h @@ -228,4 +228,10 @@ FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayNodesScheduledBefo */ - (ASDisplayNode *)_supernodeWithClass:(Class)supernodeClass checkViewHierarchy:(BOOL)checkViewHierarchy; +/** + * Convenience method to access this node's trait collection struct. Externally, users should interact + * with the trait collection via ASTraitCollection + */ +- (ASEnvironmentTraitCollection)environmentTraitCollection; + @end diff --git a/examples/ASTraitCollection/Sample/KittenNode.m b/examples/ASTraitCollection/Sample/KittenNode.m index 62d7fcdba8..98771a8cb8 100644 --- a/examples/ASTraitCollection/Sample/KittenNode.m +++ b/examples/ASTraitCollection/Sample/KittenNode.m @@ -152,9 +152,12 @@ static const CGFloat kInnerPadding = 10.0f; OverrideViewController *overrideVC = [[OverrideViewController alloc] init]; overrideVC.overrideDisplayTraitsWithTraitCollection = ^(UITraitCollection *traitCollection) { - ASTraitCollection *asyncTraitCollection = [ASTraitCollection displayTraitsWithUITraitCollection:traitCollection]; - asyncTraitCollection.horizontalSizeClass = UIUserInterfaceSizeClassCompact; - asyncTraitCollection.verticalSizeClass = UIUserInterfaceSizeClassCompact; + ASTraitCollection *asyncTraitCollection = [ASTraitCollection traitCollectionWithDisplayScale:traitCollection.displayScale + userInterfaceIdiom:traitCollection.userInterfaceIdiom + horizontalSizeClass:UIUserInterfaceSizeClassCompact + verticalSizeClass:UIUserInterfaceSizeClassCompact + forceTouchCapability:traitCollection.forceTouchCapability + traitCollectionContext:nil]; return asyncTraitCollection; };