From 298b9a2be7bc6f52755538fb9eb6a9a88cc55312 Mon Sep 17 00:00:00 2001 From: Michael Schneider Date: Wed, 20 Apr 2016 12:57:56 -0700 Subject: [PATCH 01/52] Fix ASPagerNode data source and delegate inconsistencies - Change ASPagerNodeDataSource -> ASPagerDataSource - Add ASPagerDelegate --- AsyncDisplayKit/ASCollectionView.h | 2 +- AsyncDisplayKit/ASPagerNode.h | 22 ++++++++++++++-------- AsyncDisplayKit/ASPagerNode.m | 6 +++--- AsyncDisplayKit/Details/ASDelegateProxy.m | 2 +- 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/AsyncDisplayKit/ASCollectionView.h b/AsyncDisplayKit/ASCollectionView.h index 99a4bd0548..e6f43bec3c 100644 --- a/AsyncDisplayKit/ASCollectionView.h +++ b/AsyncDisplayKit/ASCollectionView.h @@ -342,7 +342,7 @@ NS_ASSUME_NONNULL_BEGIN * This is a node-based UICollectionViewDataSource. */ #define ASCollectionViewDataSource ASCollectionDataSource -@protocol ASCollectionDataSource +@protocol ASCollectionDataSource @optional diff --git a/AsyncDisplayKit/ASPagerNode.h b/AsyncDisplayKit/ASPagerNode.h index 7b64836928..5adb5ab9fb 100644 --- a/AsyncDisplayKit/ASPagerNode.h +++ b/AsyncDisplayKit/ASPagerNode.h @@ -11,7 +11,8 @@ @class ASPagerNode; @class ASPagerFlowLayout; -@protocol ASPagerNodeDataSource +#define ASPagerNodeDataSource ASPagerDataSource +@protocol ASPagerDataSource /** * This method replaces -collectionView:numberOfItemsInSection: @@ -65,25 +66,30 @@ @end +@protocol ASPagerDelegate + +@end + @interface ASPagerNode : ASCollectionNode -// Configures a default horizontal, paging flow layout with 0 inter-item spacing. +/// Configures a default horizontal, paging flow layout with 0 inter-item spacing. - (instancetype)init; -// Initializer with custom-configured flow layout properties. +/// Initializer with custom-configured flow layout properties. - (instancetype)initWithCollectionViewLayout:(ASPagerFlowLayout *)flowLayout; -// Data Source is required, and uses a different protocol from ASCollectionNode. -- (void)setDataSource:(id )dataSource; -- (id )dataSource; +/// Data Source is required, and uses a different protocol from ASCollectionNode. +- (void)setDataSource:(id )dataSource; +- (id )dataSource; // Delegate is optional, and uses the same protocol as ASCollectionNode. // This includes UIScrollViewDelegate as well as most methods from UICollectionViewDelegate, like willDisplay... -@property (nonatomic, weak) id delegate; +@property (nonatomic, weak) id delegate; -// The underlying ASCollectionView object. +/// The underlying ASCollectionView object. @property (nonatomic, readonly) ASCollectionView *view; +/// Scroll the contents of the receiver to ensure that the page is visible. - (void)scrollToPageAtIndex:(NSInteger)index animated:(BOOL)animated; @end diff --git a/AsyncDisplayKit/ASPagerNode.m b/AsyncDisplayKit/ASPagerNode.m index 52e33bc8fa..ac8cbc593f 100644 --- a/AsyncDisplayKit/ASPagerNode.m +++ b/AsyncDisplayKit/ASPagerNode.m @@ -16,7 +16,7 @@ { ASPagerFlowLayout *_flowLayout; ASPagerNodeProxy *_proxy; - __weak id _pagerDataSource; + __weak id _pagerDataSource; BOOL _pagerDataSourceImplementsNodeBlockAtIndex; BOOL _pagerDataSourceImplementsConstrainedSizeForNode; } @@ -111,12 +111,12 @@ #pragma mark - Data Source Proxy -- (id )dataSource +- (id )dataSource { return _pagerDataSource; } -- (void)setDataSource:(id )pagerDataSource +- (void)setDataSource:(id )pagerDataSource { if (pagerDataSource != _pagerDataSource) { _pagerDataSource = pagerDataSource; diff --git a/AsyncDisplayKit/Details/ASDelegateProxy.m b/AsyncDisplayKit/Details/ASDelegateProxy.m index b4f6977525..9e2e901347 100644 --- a/AsyncDisplayKit/Details/ASDelegateProxy.m +++ b/AsyncDisplayKit/Details/ASDelegateProxy.m @@ -77,7 +77,7 @@ - (BOOL)interceptsSelector:(SEL)selector { return ( - // handled by ASPagerNodeDataSource node<->cell machinery + // handled by ASPagerDataSource node<->cell machinery selector == @selector(collectionView:nodeForItemAtIndexPath:) || selector == @selector(collectionView:nodeBlockForItemAtIndexPath:) || selector == @selector(collectionView:numberOfItemsInSection:) || From cad221007e0e898132c82d0445625a1da016ee19 Mon Sep 17 00:00:00 2001 From: Michael Schneider Date: Wed, 20 Apr 2016 13:12:19 -0700 Subject: [PATCH 02/52] Remove extending NSObject protocol in ASPagerDelegate as ASCollectionDelegate already extends it --- AsyncDisplayKit/ASPagerNode.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AsyncDisplayKit/ASPagerNode.h b/AsyncDisplayKit/ASPagerNode.h index 5adb5ab9fb..481ceaf1c6 100644 --- a/AsyncDisplayKit/ASPagerNode.h +++ b/AsyncDisplayKit/ASPagerNode.h @@ -66,7 +66,7 @@ @end -@protocol ASPagerDelegate +@protocol ASPagerDelegate @end From 29ab87a1e4a5a8d8011f36c7b71765a8ffce05a3 Mon Sep 17 00:00:00 2001 From: Michael Schneider Date: Wed, 20 Apr 2016 12:54:39 -0700 Subject: [PATCH 03/52] Fix API ASTextNode API inconsistencies - Deprecate attributedString in ASTextNode in favor of attributedText to be aligned with UILabel - Deprecate truncationAttributedString in ASTextNode in favor of truncationAttributedText to be aligned with attributedText --- AsyncDisplayKit/ASTextNode.h | 26 +++++- AsyncDisplayKit/ASTextNode.mm | 108 +++++++++++++++---------- AsyncDisplayKitTests/ASTextNodeTests.m | 18 ++--- 3 files changed, 97 insertions(+), 55 deletions(-) diff --git a/AsyncDisplayKit/ASTextNode.h b/AsyncDisplayKit/ASTextNode.h index f96bf51370..433efe61e2 100644 --- a/AsyncDisplayKit/ASTextNode.h +++ b/AsyncDisplayKit/ASTextNode.h @@ -34,19 +34,19 @@ typedef NS_ENUM(NSUInteger, ASTextNodeHighlightStyle) { @interface ASTextNode : ASControlNode /** - @abstract The attributed string to show. + @abstract The styled text displayed by the node. @discussion Defaults to nil, no text is shown. For inline image attachments, add an attribute of key NSAttachmentAttributeName, with a value of an NSTextAttachment. */ -@property (nullable, nonatomic, copy) NSAttributedString *attributedString; +@property (nullable, nonatomic, copy) NSAttributedString *attributedText; #pragma mark - Truncation /** - @abstract The attributedString to use when the text must be truncated. + @abstract The attributedText to use when the text must be truncated. @discussion Defaults to a localized ellipsis character. */ -@property (nullable, nonatomic, copy) NSAttributedString *truncationAttributedString; +@property (nullable, nonatomic, copy) NSAttributedString *truncationAttributedText; /** @summary The second attributed string appended for truncation. @@ -270,4 +270,22 @@ typedef NS_ENUM(NSUInteger, ASTextNodeHighlightStyle) { @end +/** + * @abstract Text node deprecated properties + */ +@interface ASTextNode (Deprecated) + +/** + @see attributedText + */ +@property (nullable, nonatomic, copy) NSAttributedString *attributedString; + + +/** + @see truncationAttributedText + */ +@property (nullable, nonatomic, copy) NSAttributedString *truncationAttributedString; + +@end + NS_ASSUME_NONNULL_END diff --git a/AsyncDisplayKit/ASTextNode.mm b/AsyncDisplayKit/ASTextNode.mm index b3771ba14d..83f6aad67e 100644 --- a/AsyncDisplayKit/ASTextNode.mm +++ b/AsyncDisplayKit/ASTextNode.mm @@ -67,7 +67,7 @@ static NSString *ASTextNodeTruncationTokenAttributeName = @"ASTextNodeTruncation NSArray *_exclusionPaths; - NSAttributedString *_composedTruncationString; + NSAttributedString *_composedTruncationText; NSString *_highlightedLinkAttributeName; id _highlightedLinkAttributeValue; @@ -105,7 +105,7 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ]; self.needsDisplayOnBoundsChange = YES; _truncationMode = NSLineBreakByWordWrapping; - _composedTruncationString = DefaultTruncationAttributedString(); + _composedTruncationText = DefaultTruncationAttributedString(); // The common case is for a text node to be non-opaque and blended over some background. self.opaque = NO; @@ -158,8 +158,8 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ]; - (NSString *)description { - NSString *plainString = [[_attributedString string] stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]]; - NSString *truncationString = [_composedTruncationString string]; + NSString *plainString = [[_attributedText string] stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]]; + NSString *truncationString = [_composedTruncationText string]; if (plainString.length > 50) plainString = [[plainString substringToIndex:50] stringByAppendingString:@"\u2026"]; return [NSString stringWithFormat:@"<%@: %p; text = \"%@\"; truncation string = \"%@\"; frame = %@; renderer = %p>", self.class, self, plainString, truncationString, self.nodeLoaded ? NSStringFromCGRect(self.layer.frame) : nil, _renderer]; @@ -237,8 +237,8 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ]; - (ASTextKitAttributes)_rendererAttributes { return { - .attributedString = _attributedString, - .truncationAttributedString = _composedTruncationString, + .attributedString = _attributedText, + .truncationAttributedString = _composedTruncationText, .lineBreakMode = _truncationMode, .maximumNumberOfLines = _maximumNumberOfLines, .exclusionPaths = _exclusionPaths, @@ -340,10 +340,10 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ]; [self setNeedsDisplay]; CGSize size = [[self _renderer] size]; - if (self.attributedString.length > 0) { + if (_attributedText.length > 0) { CGFloat screenScale = ASScreenScale(); - self.ascender = round([[_attributedString attribute:NSFontAttributeName atIndex:0 effectiveRange:NULL] ascender] * screenScale)/screenScale; - self.descender = round([[_attributedString attribute:NSFontAttributeName atIndex:_attributedString.length - 1 effectiveRange:NULL] descender] * screenScale)/screenScale; + self.ascender = round([[_attributedText attribute:NSFontAttributeName atIndex:0 effectiveRange:NULL] ascender] * screenScale)/screenScale; + self.descender = round([[_attributedText attribute:NSFontAttributeName atIndex:_attributedText.length - 1 effectiveRange:NULL] descender] * screenScale)/screenScale; if (_renderer.currentScaleFactor > 0 && _renderer.currentScaleFactor < 1.0) { // while not perfect, this is a good estimate of what the ascender of the scaled font will be. self.ascender *= _renderer.currentScaleFactor; @@ -355,28 +355,28 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ]; #pragma mark - Modifying User Text -- (void)setAttributedString:(NSAttributedString *)attributedString +- (void)setAttributedText:(NSAttributedString *)attributedText { - if (attributedString == nil) { - attributedString = [[NSAttributedString alloc] initWithString:@"" attributes:nil]; + if (attributedText == nil) { + attributedText = [[NSAttributedString alloc] initWithString:@"" attributes:nil]; } - if (ASObjectIsEqual(attributedString, _attributedString)) { + if (ASObjectIsEqual(attributedText, _attributedText)) { return; } - _attributedString = ASCleanseAttributedStringOfCoreTextAttributes(attributedString); + _attributedText = ASCleanseAttributedStringOfCoreTextAttributes(attributedText); - if (_attributedString.length > 0) { + if (_attributedText.length > 0) { CGFloat screenScale = ASScreenScale(); - self.ascender = round([[_attributedString attribute:NSFontAttributeName atIndex:0 effectiveRange:NULL] ascender] * screenScale)/screenScale; - self.descender = round([[_attributedString attribute:NSFontAttributeName atIndex:_attributedString.length - 1 effectiveRange:NULL] descender] * screenScale)/screenScale; + self.ascender = round([[_attributedText attribute:NSFontAttributeName atIndex:0 effectiveRange:NULL] ascender] * screenScale)/screenScale; + self.descender = round([[_attributedText attribute:NSFontAttributeName atIndex:_attributedText.length - 1 effectiveRange:NULL] descender] * screenScale)/screenScale; } // Sync the truncation string with attributes from the updated _attributedString // Without this, the size calculation of the text with truncation applied will - // not take into account the attributes of attributedString in the last line - [self _updateComposedTruncationString]; + // not take into account the attributes of attributedText in the last line + [self _updateComposedTruncationText]; // We need an entirely new renderer [self _invalidateRenderer]; @@ -386,10 +386,10 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ]; [self setNeedsDisplay]; - self.accessibilityLabel = _attributedString.string; + self.accessibilityLabel = _attributedText.string; // We're an accessibility element by default if there is a string. - self.isAccessibilityElement = _attributedString.length != 0; + self.isAccessibilityElement = _attributedText.length != 0; } #pragma mark - Text Layout @@ -470,7 +470,7 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ]; { ASTextKitRenderer *renderer = [self _renderer]; NSRange visibleRange = renderer.visibleRanges[0]; - NSAttributedString *attributedString = _attributedString; + NSAttributedString *attributedString = _attributedText; NSRange clampedRange = NSIntersectionRange(visibleRange, NSMakeRange(0, attributedString.length)); // Check in a 9-point region around the actual touch point so we make sure @@ -1023,14 +1023,14 @@ static NSAttributedString *DefaultTruncationAttributedString() return defaultTruncationAttributedString; } -- (void)setTruncationAttributedString:(NSAttributedString *)truncationAttributedString +- (void)setTruncationAttributedText:(NSAttributedString *)truncationAttributedText { - if (ASObjectIsEqual(_truncationAttributedString, truncationAttributedString)) { + if (ASObjectIsEqual(_truncationAttributedText, truncationAttributedText)) { return; } - _truncationAttributedString = [truncationAttributedString copy]; - [self _invalidateTruncationString]; + _truncationAttributedText = [truncationAttributedText copy]; + [self _invalidateTruncationText]; } - (void)setAdditionalTruncationMessage:(NSAttributedString *)additionalTruncationMessage @@ -1040,7 +1040,7 @@ static NSAttributedString *DefaultTruncationAttributedString() } _additionalTruncationMessage = [additionalTruncationMessage copy]; - [self _invalidateTruncationString]; + [self _invalidateTruncationText]; } - (void)setTruncationMode:(NSLineBreakMode)truncationMode @@ -1055,7 +1055,7 @@ static NSAttributedString *DefaultTruncationAttributedString() - (BOOL)isTruncated { NSRange visibleRange = [self _renderer].visibleRanges[0]; - return visibleRange.length < _attributedString.length; + return visibleRange.length < _attributedText.length; } - (void)setPointSizeScaleFactors:(NSArray *)pointSizeScaleFactors @@ -1082,14 +1082,14 @@ static NSAttributedString *DefaultTruncationAttributedString() #pragma mark - Truncation Message -- (void)_updateComposedTruncationString +- (void)_updateComposedTruncationText { - _composedTruncationString = [self _prepareTruncationStringForDrawing:[self _composedTruncationString]]; + _composedTruncationText = [self _prepareTruncationStringForDrawing:[self _composedTruncationText]]; } -- (void)_invalidateTruncationString +- (void)_invalidateTruncationText { - [self _updateComposedTruncationString]; + [self _updateComposedTruncationText]; [self _invalidateRenderer]; [self setNeedsDisplay]; } @@ -1111,7 +1111,7 @@ static NSAttributedString *DefaultTruncationAttributedString() NSUInteger additionalTruncationMessageLength = _additionalTruncationMessage.length; // We get the location of the truncation token, then add the length of the // truncation attributed string +1 for the space between. - NSRange range = NSMakeRange(truncationTokenIndex + _truncationAttributedString.length + 1, additionalTruncationMessageLength); + NSRange range = NSMakeRange(truncationTokenIndex + _truncationAttributedText.length + 1, additionalTruncationMessageLength); return range; } @@ -1120,24 +1120,24 @@ static NSAttributedString *DefaultTruncationAttributedString() * additional truncation message and a truncation attributed string, they will * be properly composed. */ -- (NSAttributedString *)_composedTruncationString +- (NSAttributedString *)_composedTruncationText { //If we have neither return the default - if (!_additionalTruncationMessage && !_truncationAttributedString) { - return _composedTruncationString; + if (!_additionalTruncationMessage && !_truncationAttributedText) { + return _composedTruncationText; } // Short circuit if we only have one or the other. if (!_additionalTruncationMessage) { - return _truncationAttributedString; + return _truncationAttributedText; } - if (!_truncationAttributedString) { + if (!_truncationAttributedText) { return _additionalTruncationMessage; } // If we've reached this point, both _additionalTruncationMessage and // _truncationAttributedString are present. Compose them. - NSMutableAttributedString *newComposedTruncationString = [[NSMutableAttributedString alloc] initWithAttributedString:_truncationAttributedString]; + NSMutableAttributedString *newComposedTruncationString = [[NSMutableAttributedString alloc] initWithAttributedString:_truncationAttributedText]; [newComposedTruncationString replaceCharactersInRange:NSMakeRange(newComposedTruncationString.length, 0) withString:@" "]; [newComposedTruncationString appendAttributedString:_additionalTruncationMessage]; return newComposedTruncationString; @@ -1153,9 +1153,9 @@ static NSAttributedString *DefaultTruncationAttributedString() truncationString = ASCleanseAttributedStringOfCoreTextAttributes(truncationString); NSMutableAttributedString *truncationMutableString = [truncationString mutableCopy]; // Grab the attributes from the full string - if (_attributedString.length > 0) { - NSAttributedString *originalString = _attributedString; - NSInteger originalStringLength = _attributedString.length; + if (_attributedText.length > 0) { + NSAttributedString *originalString = _truncationAttributedText; + NSInteger originalStringLength = _truncationAttributedText.length; // Add any of the original string's attributes to the truncation string, // but don't overwrite any of the truncation string's attributes NSDictionary *originalStringAttributes = [originalString attributesAtIndex:originalStringLength-1 effectiveRange:NULL]; @@ -1170,3 +1170,27 @@ static NSAttributedString *DefaultTruncationAttributedString() } @end + +@implementation ASTextNode (Deprecated) + +- (void)setAttributedString:(NSAttributedString *)attributedString +{ + self.attributedText = attributedString; +} + +- (NSAttributedString *)attributedString +{ + return self.attributedText; +} + +- (void)setTruncationAttributedString:(NSAttributedString *)truncationAttributedString +{ + self.truncationAttributedText = truncationAttributedString; +} + +- (NSAttributedString *)truncationAttributedString +{ + return self.truncationAttributedText; +} + +@end diff --git a/AsyncDisplayKitTests/ASTextNodeTests.m b/AsyncDisplayKitTests/ASTextNodeTests.m index a5c03ca0b9..6696d7c507 100644 --- a/AsyncDisplayKitTests/ASTextNodeTests.m +++ b/AsyncDisplayKitTests/ASTextNodeTests.m @@ -44,7 +44,7 @@ static BOOL CGSizeEqualToSizeWithIn(CGSize size1, CGSize size2, CGFloat delta) @interface ASTextNodeTests : XCTestCase @property (nonatomic, readwrite, strong) ASTextNode *textNode; -@property (nonatomic, readwrite, copy) NSAttributedString *attributedString; +@property (nonatomic, readwrite, copy) NSAttributedString *attributedText; @end @@ -80,8 +80,8 @@ static BOOL CGSizeEqualToSizeWithIn(CGSize size1, CGSize size2, CGFloat delta) [mas addAttribute:NSParagraphStyleAttributeName value:lastLinePara range:NSMakeRange(mas.length - 1, 1)]; - _attributedString = mas; - _textNode.attributedString = _attributedString; + _attributedText = mas; + _textNode.attributedText = _attributedText; } #pragma mark - ASTextNode @@ -97,8 +97,8 @@ static BOOL CGSizeEqualToSizeWithIn(CGSize size1, CGSize size2, CGFloat delta) - (void)testSettingTruncationMessage { NSAttributedString *truncation = [[NSAttributedString alloc] initWithString:@"..." attributes:nil]; - _textNode.truncationAttributedString = truncation; - XCTAssertTrue([_textNode.truncationAttributedString isEqualToAttributedString:truncation], @"Failed to set truncation message"); + _textNode.truncationAttributedText = truncation; + XCTAssertTrue([_textNode.truncationAttributedText isEqualToAttributedString:truncation], @"Failed to set truncation message"); } - (void)testSettingAdditionalTruncationMessage @@ -142,11 +142,11 @@ static BOOL CGSizeEqualToSizeWithIn(CGSize size1, CGSize size2, CGFloat delta) - (void)testAccessibility { - _textNode.attributedString = _attributedString; + _textNode.attributedText = _attributedText; XCTAssertTrue(_textNode.isAccessibilityElement, @"Should be an accessibility element"); XCTAssertTrue(_textNode.accessibilityTraits == UIAccessibilityTraitStaticText, @"Should have static text accessibility trait, instead has %llu", _textNode.accessibilityTraits); - XCTAssertTrue([_textNode.accessibilityLabel isEqualToString:_attributedString.string], @"Accessibility label is incorrectly set to \n%@\n when it should be \n%@\n", _textNode.accessibilityLabel, _attributedString.string); + XCTAssertTrue([_textNode.accessibilityLabel isEqualToString:_attributedText.string], @"Accessibility label is incorrectly set to \n%@\n when it should be \n%@\n", _textNode.accessibilityLabel, _attributedText.string); } - (void)testLinkAttribute @@ -156,7 +156,7 @@ static BOOL CGSizeEqualToSizeWithIn(CGSize size1, CGSize size2, CGFloat delta) NSString *linkString = @"Link"; NSRange linkRange = NSMakeRange(0, linkString.length); NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:linkString attributes:@{ linkAttributeName : linkAttributeValue}]; - _textNode.attributedString = attributedString; + _textNode.attributedText = attributedString; _textNode.linkAttributeNames = @[linkAttributeName]; ASTextNodeTestDelegate *delegate = [ASTextNodeTestDelegate new]; @@ -178,7 +178,7 @@ static BOOL CGSizeEqualToSizeWithIn(CGSize size1, CGSize size2, CGFloat delta) NSString *linkString = @"Link notalink"; NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:linkString]; [attributedString addAttribute:linkAttributeName value:linkAttributeValue range:NSMakeRange(0, 4)]; - _textNode.attributedString = attributedString; + _textNode.attributedText = attributedString; _textNode.linkAttributeNames = @[linkAttributeName]; ASTextNodeTestDelegate *delegate = [ASTextNodeTestDelegate new]; From 90c3dbc3247d72b8ff10e3c1a7a1264b1d173c30 Mon Sep 17 00:00:00 2001 From: Michael Schneider Date: Wed, 20 Apr 2016 14:04:37 -0700 Subject: [PATCH 04/52] Add better comments for deprecated ASTextNode properties --- AsyncDisplayKit/ASTextNode.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/AsyncDisplayKit/ASTextNode.h b/AsyncDisplayKit/ASTextNode.h index 433efe61e2..b9fff20556 100644 --- a/AsyncDisplayKit/ASTextNode.h +++ b/AsyncDisplayKit/ASTextNode.h @@ -276,12 +276,18 @@ typedef NS_ENUM(NSUInteger, ASTextNodeHighlightStyle) { @interface ASTextNode (Deprecated) /** + The attributedString and attributedText properties are equivalent, but attributedText is now the standard API + name in order to match UILabel and ASEditableTextNode. + @see attributedText */ @property (nullable, nonatomic, copy) NSAttributedString *attributedString; /** + The truncationAttributedString and truncationAttributedText properties are equivalent, but attributedText is now the + standard API name in order to match UILabel and ASEditableTextNode. + @see truncationAttributedText */ @property (nullable, nonatomic, copy) NSAttributedString *truncationAttributedString; From bc8489528e22de617d9f708619a354c5cf511241 Mon Sep 17 00:00:00 2001 From: Michael Schneider Date: Wed, 4 May 2016 18:27:06 -0700 Subject: [PATCH 05/52] Fix crash in delegate / dataSource proxies for ASCollectionView and ASTableView --- AsyncDisplayKit/ASCollectionView.mm | 18 +++++++----------- AsyncDisplayKit/ASTableView.mm | 17 ++++++----------- AsyncDisplayKit/Details/ASDelegateProxy.m | 10 +++++++++- 3 files changed, 22 insertions(+), 23 deletions(-) diff --git a/AsyncDisplayKit/ASCollectionView.mm b/AsyncDisplayKit/ASCollectionView.mm index 950cba8f76..b5a246e794 100644 --- a/AsyncDisplayKit/ASCollectionView.mm +++ b/AsyncDisplayKit/ASCollectionView.mm @@ -343,10 +343,10 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; { // Note: It's common to check if the value hasn't changed and short-circuit but we aren't doing that here to handle // the (common) case of nilling the asyncDataSource in the ViewController's dealloc. In this case our _asyncDataSource - // will return as nil (ARC magic) even though the _proxyDataSource still exists. It's really important to nil out - // super.dataSource in this case because calls to ASCollectionViewProxy will start failing and cause crashes. - - super.dataSource = nil; + // will return as nil (ARC magic) even though the _proxyDataSource still exists. It's really important to hold a strong + // reference to the old dataSource in this case because calls to ASCollectionViewProxy will start failing and cause crashes. + NS_VALID_UNTIL_END_OF_SCOPE id oldDataSource = super.dataSource; + if (asyncDataSource == nil) { _asyncDataSource = nil; _proxyDataSource = _isDeallocating ? nil : [[ASCollectionViewProxy alloc] initWithTarget:nil interceptor:self]; @@ -375,13 +375,9 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; { // Note: It's common to check if the value hasn't changed and short-circuit but we aren't doing that here to handle // the (common) case of nilling the asyncDelegate in the ViewController's dealloc. In this case our _asyncDelegate - // will return as nil (ARC magic) even though the _proxyDelegate still exists. It's really important to nil out - // super.delegate in this case because calls to ASCollectionViewProxy will start failing and cause crashes. - - // Order is important here, the asyncDelegate must be callable while nilling super.delegate to avoid random crashes - // in UIScrollViewAccessibility. - - super.delegate = nil; + // will return as nil (ARC magic) even though the _proxyDataSource still exists. It's really important to hold a strong + // reference to the old delegate in this case because calls to ASCollectionViewProxy will start failing and cause crashes. + NS_VALID_UNTIL_END_OF_SCOPE id oldDelegate = super.delegate; if (asyncDelegate == nil) { _asyncDelegate = nil; diff --git a/AsyncDisplayKit/ASTableView.mm b/AsyncDisplayKit/ASTableView.mm index c0449da6c4..59066323bd 100644 --- a/AsyncDisplayKit/ASTableView.mm +++ b/AsyncDisplayKit/ASTableView.mm @@ -268,10 +268,9 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; { // Note: It's common to check if the value hasn't changed and short-circuit but we aren't doing that here to handle // the (common) case of nilling the asyncDataSource in the ViewController's dealloc. In this case our _asyncDataSource - // will return as nil (ARC magic) even though the _proxyDataSource still exists. It's really important to nil out - // super.dataSource in this case because calls to ASTableViewProxy will start failing and cause crashes. - - super.dataSource = nil; + // will return as nil (ARC magic) even though the _proxyDataSource still exists. It's really important to hold a strong + // reference to the old dataSource in this case because calls to ASTableViewProxy will start failing and cause crashes. + NS_VALID_UNTIL_END_OF_SCOPE id oldDataSource = self.dataSource; if (asyncDataSource == nil) { _asyncDataSource = nil; @@ -299,13 +298,9 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; { // Note: It's common to check if the value hasn't changed and short-circuit but we aren't doing that here to handle // the (common) case of nilling the asyncDelegate in the ViewController's dealloc. In this case our _asyncDelegate - // will return as nil (ARC magic) even though the _proxyDelegate still exists. It's really important to nil out - // super.delegate in this case because calls to ASTableViewProxy will start failing and cause crashes. - - // Order is important here, the asyncDelegate must be callable while nilling super.delegate to avoid random crashes - // in UIScrollViewAccessibility. - - super.delegate = nil; + // will return as nil (ARC magic) even though the _proxyDataSource still exists. It's really important to hold a strong + // reference to the old delegate in this case because calls to ASTableViewProxy will start failing and cause crashes. + NS_VALID_UNTIL_END_OF_SCOPE id oldDelegate = super.delegate; if (asyncDelegate == nil) { _asyncDelegate = nil; diff --git a/AsyncDisplayKit/Details/ASDelegateProxy.m b/AsyncDisplayKit/Details/ASDelegateProxy.m index b4f6977525..92501f19a6 100644 --- a/AsyncDisplayKit/Details/ASDelegateProxy.m +++ b/AsyncDisplayKit/Details/ASDelegateProxy.m @@ -125,7 +125,15 @@ if (_target) { return [_target respondsToSelector:aSelector] ? _target : nil; } else { - [_interceptor proxyTargetHasDeallocated:self]; + // The _interceptor needs to be nilled out in this scenario. For that a strong reference needs to be created + // to be able to nil out the _interceptor but still let it know that the proxy target has deallocated + // We have to hold a strong reference to the interceptor as we have to nil it out and call the proxyTargetHasDeallocated + // The reason that the interceptor needs to be nilled out is that there maybe a change of a infinite loop, for example + // if a method will be called in the proxyTargetHasDeallocated: that again would trigger a whole new forwarding cycle + id interceptor = _interceptor; + _interceptor = nil; + [interceptor proxyTargetHasDeallocated:self]; + return nil; } } From cac4ed56264781e911b66201a68764b9a6d065fa Mon Sep 17 00:00:00 2001 From: Michael Schneider Date: Thu, 5 May 2016 16:49:01 -0700 Subject: [PATCH 06/52] Move layout of ASVideoNode to layout specs - This should fix adjusting a custom play button position - Fix sample project use of ASVideoNode --- AsyncDisplayKit/ASVideoNode.mm | 111 ++++++++++++++-------- examples/Videos/Sample/ViewController.m | 121 ++++++++++++++---------- 2 files changed, 145 insertions(+), 87 deletions(-) diff --git a/AsyncDisplayKit/ASVideoNode.mm b/AsyncDisplayKit/ASVideoNode.mm index 44ba2e88d7..90c41b62aa 100644 --- a/AsyncDisplayKit/ASVideoNode.mm +++ b/AsyncDisplayKit/ASVideoNode.mm @@ -64,9 +64,9 @@ static NSString * const kStatus = @"status"; ASImageNode *_placeholderImageNode; // TODO: Make ASVideoNode an ASImageNode subclass; remove this. - ASButtonNode *_playButton; + ASButtonNode *_playButtonNode; ASDisplayNode *_playerNode; - ASDisplayNode *_spinner; + ASDisplayNode *_spinnerNode; NSString *_gravity; } @@ -185,6 +185,45 @@ static NSString * const kStatus = @"status"; [notificationCenter removeObserver:self name:AVPlayerItemNewErrorLogEntryNotification object:playerItem]; } +- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize +{ + // All subnodes should taking the whole node frame + CGSize maxSize = constrainedSize.max; + if (!CGSizeEqualToSize(self.preferredFrameSize, CGSizeZero)) { + maxSize = self.preferredFrameSize; + } + + // Prevent crashes through if infinite width or height + if (isinf(maxSize.width) || isinf(maxSize.height)) { + ASDisplayNodeAssert(NO, @"Infinite width or height in ASVideoNode"); + maxSize = CGSizeZero; + } + + // Stretch out play button, placeholder image player node to the max size + NSMutableArray *children = [NSMutableArray array]; + if (_playButtonNode) { + _playButtonNode.preferredFrameSize = maxSize; + [children addObject:_playButtonNode]; + } + if (_placeholderImageNode) { + _placeholderImageNode.preferredFrameSize = maxSize; + [children addObject:_placeholderImageNode]; + } + if (_playerNode) { + _playerNode.preferredFrameSize = maxSize; + [children addObject:_playerNode]; + } + + // Center spinner node + if (_spinnerNode) { + ASCenterLayoutSpec *centerLayoutSpec = [ASCenterLayoutSpec centerLayoutSpecWithCenteringOptions:ASCenterLayoutSpecCenteringXY sizingOptions:ASCenterLayoutSpecSizingOptionDefault child:_spinnerNode]; + centerLayoutSpec.sizeRange = ASRelativeSizeRangeMakeWithExactCGSize(maxSize); + [children addObject:_spinnerNode]; + } + + return [ASStaticLayoutSpec staticLayoutSpecWithChildren:children]; +} + - (void)layout { [super layout]; @@ -192,17 +231,9 @@ static NSString * const kStatus = @"status"; CGRect bounds = self.bounds; ASDN::MutexLocker l(_videoLock); - - _placeholderImageNode.frame = bounds; - _playerNode.frame = bounds; - _playButton.frame = bounds; - - CGFloat horizontalDiff = (bounds.size.width - _playButton.bounds.size.width)/2; - CGFloat verticalDiff = (bounds.size.height - _playButton.bounds.size.height)/2; - _playButton.hitTestSlop = UIEdgeInsetsMake(-verticalDiff, -horizontalDiff, -verticalDiff, -horizontalDiff); - - _spinner.bounds = CGRectMake(0, 0, 44, 44); - _spinner.position = CGPointMake(bounds.size.width/2, bounds.size.height/2); + CGFloat horizontalDiff = (CGRectGetWidth(bounds) - CGRectGetWidth(_playButtonNode.bounds))/2; + CGFloat verticalDiff = (CGRectGetHeight(bounds) - CGRectGetHeight(_playButtonNode.bounds))/2; + _playButtonNode.hitTestSlop = UIEdgeInsetsMake(-verticalDiff, -horizontalDiff, -verticalDiff, -horizontalDiff); } - (void)generatePlaceholderImage @@ -370,6 +401,7 @@ static NSString * const kStatus = @"status"; #pragma mark - Video Properties + - (void)setPlayerState:(ASVideoNodePlayerState)playerState { ASDN::MutexLocker l(_videoLock); @@ -385,28 +417,26 @@ static NSString * const kStatus = @"status"; } _playerState = playerState; - } - (void)setPlayButton:(ASButtonNode *)playButton { ASDN::MutexLocker l(_videoLock); - [_playButton removeTarget:self action:@selector(tapped) forControlEvents:ASControlNodeEventTouchUpInside]; - [_playButton removeFromSupernode]; + [_playButtonNode removeTarget:self action:@selector(tapped) forControlEvents:ASControlNodeEventTouchUpInside]; + [_playButtonNode removeFromSupernode]; + + _playButtonNode = playButton; + [_playButtonNode addTarget:self action:@selector(tapped) forControlEvents:ASControlNodeEventTouchUpInside]; - _playButton = playButton; - [self addSubnode:playButton]; - - [_playButton addTarget:self action:@selector(tapped) forControlEvents:ASControlNodeEventTouchUpInside]; + [self setNeedsLayout]; } - (ASButtonNode *)playButton { ASDN::MutexLocker l(_videoLock); - - return _playButton; + return _playButtonNode; } - (void)setAsset:(AVAsset *)asset @@ -471,14 +501,12 @@ static NSString * const kStatus = @"status"; - (NSString *)gravity { ASDN::MutexLocker l(_videoLock); - return _gravity; } - (BOOL)muted { ASDN::MutexLocker l(_videoLock); - return _muted; } @@ -507,11 +535,13 @@ static NSString * const kStatus = @"status"; if (_playerNode == nil) { _playerNode = [self constructPlayerNode]; - if (_playButton.supernode == self) { - [self insertSubnode:_playerNode belowSubnode:_playButton]; + if (_playButtonNode.supernode == self) { + [self insertSubnode:_playerNode belowSubnode:_playButtonNode]; } else { [self addSubnode:_playerNode]; } + + [self setNeedsLayout]; } @@ -519,7 +549,7 @@ static NSString * const kStatus = @"status"; _shouldBePlaying = YES; [UIView animateWithDuration:0.15 animations:^{ - _playButton.alpha = 0.0; + _playButtonNode.alpha = 0.0; }]; if (![self ready]) { [self showSpinner]; @@ -538,28 +568,29 @@ static NSString * const kStatus = @"status"; { ASDN::MutexLocker l(_videoLock); - if (!_spinner) { - _spinner = [[ASDisplayNode alloc] initWithViewBlock:^UIView *{ + if (!_spinnerNode) { + _spinnerNode = [[ASDisplayNode alloc] initWithViewBlock:^UIView *{ UIActivityIndicatorView *spinnnerView = [[UIActivityIndicatorView alloc] init]; spinnnerView.color = [UIColor whiteColor]; - return spinnnerView; }]; - - [self addSubnode:_spinner]; + _spinnerNode.preferredFrameSize = CGSizeMake(44.0, 44.0); + + [self addSubnode:_spinnerNode]; + [self setNeedsLayout]; } - [(UIActivityIndicatorView *)_spinner.view startAnimating]; + [(UIActivityIndicatorView *)_spinnerNode.view startAnimating]; } - (void)removeSpinner { ASDN::MutexLocker l(_videoLock); - if (!_spinner) { + if (!_spinnerNode) { return; } - [_spinner removeFromSupernode]; - _spinner = nil; + [_spinnerNode removeFromSupernode]; + _spinnerNode = nil; } - (void)pause @@ -573,7 +604,7 @@ static NSString * const kStatus = @"status"; [self removeSpinner]; _shouldBePlaying = NO; [UIView animateWithDuration:0.15 animations:^{ - _playButton.alpha = 1.0; + _playButtonNode.alpha = 1.0; }]; } @@ -634,7 +665,7 @@ static NSString * const kStatus = @"status"; - (ASDisplayNode *)spinner { ASDN::MutexLocker l(_videoLock); - return _spinner; + return _spinnerNode; } - (ASImageNode *)placeholderImageNode @@ -670,6 +701,8 @@ static NSString * const kStatus = @"status"; { ASDN::MutexLocker l(_videoLock); _playerNode = playerNode; + + [self setNeedsLayout]; } - (void)setPlayer:(AVPlayer *)player @@ -698,7 +731,7 @@ static NSString * const kStatus = @"status"; { [_player removeTimeObserver:_timeObserver]; _timeObserver = nil; - [_playButton removeTarget:self action:@selector(tapped) forControlEvents:ASControlNodeEventTouchUpInside]; + [_playButtonNode removeTarget:self action:@selector(tapped) forControlEvents:ASControlNodeEventTouchUpInside]; [self removePlayerItemObservers:_currentPlayerItem]; } diff --git a/examples/Videos/Sample/ViewController.m b/examples/Videos/Sample/ViewController.m index 7a22c5e22d..d34984c76f 100644 --- a/examples/Videos/Sample/ViewController.m +++ b/examples/Videos/Sample/ViewController.m @@ -10,101 +10,125 @@ */ #import "ViewController.h" +#import "ASLayoutSpec.h" +#import "ASStaticLayoutSpec.h" @interface ViewController() +@property (nonatomic, strong) ASDisplayNode *rootNode; @property (nonatomic, strong) ASVideoNode *guitarVideoNode; @end @implementation ViewController +#pragma mark - UIViewController + - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; + + // Root node for the view controller + _rootNode = [ASDisplayNode new]; + _rootNode.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - [self.view addSubnode:self.guitarVideoNode]; + ASVideoNode *guitarVideoNode = self.guitarVideoNode; + [_rootNode addSubnode:self.guitarVideoNode]; - ASVideoNode *nicCageVideo = [self nicCageVideo]; - [self.view addSubnode:nicCageVideo]; + ASVideoNode *nicCageVideoNode = self.nicCageVideoNode; + [_rootNode addSubnode:nicCageVideoNode]; - ASVideoNode *simonVideo = [self simonVideo]; - [self.view addSubnode:simonVideo]; + // Video node with custom play button + ASVideoNode *simonVideoNode = self.simonVideoNode; + simonVideoNode.playButton = self.playButton; + [_rootNode addSubnode:simonVideoNode]; + + _rootNode.layoutSpecBlock = ^ASLayoutSpec *(ASDisplayNode * _Nonnull node, ASSizeRange constrainedSize) { + guitarVideoNode.layoutPosition = CGPointMake(0, 0); + guitarVideoNode.preferredFrameSize = CGSizeMake([UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height/3); + + nicCageVideoNode.layoutPosition = CGPointMake([UIScreen mainScreen].bounds.size.width/2, [UIScreen mainScreen].bounds.size.height/3); + nicCageVideoNode.preferredFrameSize = CGSizeMake([UIScreen mainScreen].bounds.size.width/2, [UIScreen mainScreen].bounds.size.height/3); + + simonVideoNode.layoutPosition = CGPointMake(0, [UIScreen mainScreen].bounds.size.height - ([UIScreen mainScreen].bounds.size.height/3)); + simonVideoNode.preferredFrameSize = CGSizeMake([UIScreen mainScreen].bounds.size.width/2, [UIScreen mainScreen].bounds.size.height/3); + return [ASStaticLayoutSpec staticLayoutSpecWithChildren:@[guitarVideoNode, nicCageVideoNode, simonVideoNode]]; + }; + [self.view addSubnode:_rootNode]; } +- (void)viewDidLayoutSubviews +{ + [super viewDidLayoutSubviews]; + + // After all subviews are layed out we have to measure it and move the root node to the right place + CGSize viewSize = self.view.bounds.size; + [self.rootNode measureWithSizeRange:ASSizeRangeMake(viewSize, viewSize)]; + [self.rootNode setNeedsLayout]; +} + +#pragma mark - Getter / Setter + - (ASVideoNode *)guitarVideoNode; { if (_guitarVideoNode) { return _guitarVideoNode; } + _guitarVideoNode = [[ASVideoNode alloc] init]; - _guitarVideoNode.asset = [AVAsset assetWithURL:[NSURL URLWithString:@"https://files.parsetfss.com/8a8a3b0c-619e-4e4d-b1d5-1b5ba9bf2b42/tfss-3045b261-7e93-4492-b7e5-5d6358376c9f-editedLiveAndDie.mov"]]; - - _guitarVideoNode.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height/3); - _guitarVideoNode.gravity = AVLayerVideoGravityResizeAspectFill; - _guitarVideoNode.backgroundColor = [UIColor lightGrayColor]; - _guitarVideoNode.periodicTimeObserverTimescale = 1; //Default is 100 - _guitarVideoNode.delegate = self; return _guitarVideoNode; } -- (ASVideoNode *)nicCageVideo; +- (ASVideoNode *)nicCageVideoNode; { - ASVideoNode *nicCageVideo = [[ASVideoNode alloc] init]; + ASVideoNode *nicCageVideoNode = [[ASVideoNode alloc] init]; + nicCageVideoNode.delegate = self; + nicCageVideoNode.asset = [AVAsset assetWithURL:[NSURL URLWithString:@"https://files.parsetfss.com/8a8a3b0c-619e-4e4d-b1d5-1b5ba9bf2b42/tfss-753fe655-86bb-46da-89b7-aa59c60e49c0-niccage.mp4"]]; + nicCageVideoNode.gravity = AVLayerVideoGravityResize; + nicCageVideoNode.backgroundColor = [UIColor lightGrayColor]; + nicCageVideoNode.shouldAutorepeat = YES; + nicCageVideoNode.shouldAutoplay = YES; + nicCageVideoNode.muted = YES; - nicCageVideo.delegate = self; - - nicCageVideo.asset = [AVAsset assetWithURL:[NSURL URLWithString:@"https://files.parsetfss.com/8a8a3b0c-619e-4e4d-b1d5-1b5ba9bf2b42/tfss-753fe655-86bb-46da-89b7-aa59c60e49c0-niccage.mp4"]]; - - nicCageVideo.frame = CGRectMake([UIScreen mainScreen].bounds.size.width/2, [UIScreen mainScreen].bounds.size.height/3, [UIScreen mainScreen].bounds.size.width/2, [UIScreen mainScreen].bounds.size.height/3); - - nicCageVideo.gravity = AVLayerVideoGravityResize; - - nicCageVideo.backgroundColor = [UIColor lightGrayColor]; - nicCageVideo.shouldAutorepeat = YES; - nicCageVideo.shouldAutoplay = YES; - nicCageVideo.muted = YES; - - return nicCageVideo; + return nicCageVideoNode; } -- (ASVideoNode *)simonVideo; +- (ASVideoNode *)simonVideoNode { - ASVideoNode *simonVideo = [[ASVideoNode alloc] init]; + ASVideoNode *simonVideoNode = [[ASVideoNode alloc] init]; NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"simon" ofType:@"mp4"]]; - simonVideo.asset = [AVAsset assetWithURL:url]; + simonVideoNode.asset = [AVAsset assetWithURL:url]; + simonVideoNode.gravity = AVLayerVideoGravityResizeAspect; + simonVideoNode.backgroundColor = [UIColor lightGrayColor]; + simonVideoNode.shouldAutorepeat = YES; + simonVideoNode.shouldAutoplay = YES; + simonVideoNode.muted = YES; - simonVideo.frame = CGRectMake(0, [UIScreen mainScreen].bounds.size.height - ([UIScreen mainScreen].bounds.size.height/3), [UIScreen mainScreen].bounds.size.width/2, [UIScreen mainScreen].bounds.size.height/3); - - simonVideo.gravity = AVLayerVideoGravityResizeAspect; - - simonVideo.backgroundColor = [UIColor lightGrayColor]; - simonVideo.shouldAutorepeat = YES; - simonVideo.shouldAutoplay = YES; - simonVideo.muted = YES; - - return simonVideo; + return simonVideoNode; } - (ASButtonNode *)playButton; { - ASButtonNode *playButton = [[ASButtonNode alloc] init]; + ASButtonNode *playButtonNode = [[ASButtonNode alloc] init]; UIImage *image = [UIImage imageNamed:@"playButton@2x.png"]; - [playButton setImage:image forState:ASControlStateNormal]; - [playButton measure:CGSizeMake(50, 50)]; - playButton.bounds = CGRectMake(0, 0, playButton.calculatedSize.width, playButton.calculatedSize.height); - playButton.position = CGPointMake([UIScreen mainScreen].bounds.size.width/4, ([UIScreen mainScreen].bounds.size.height/3)/2); - [playButton setImage:[UIImage imageNamed:@"playButtonSelected@2x.png"] forState:ASControlStateHighlighted]; + [playButtonNode setImage:image forState:ASControlStateNormal]; + [playButtonNode setImage:[UIImage imageNamed:@"playButtonSelected@2x.png"] forState:ASControlStateHighlighted]; - return playButton; + // Change placement of play button if necessary + //playButtonNode.contentHorizontalAlignment = ASHorizontalAlignmentStart; + //playButtonNode.contentVerticalAlignment = ASVerticalAlignmentCenter; + + return playButtonNode; } +#pragma mark - Actions + - (void)videoNodeWasTapped:(ASVideoNode *)videoNode { if (videoNode == self.guitarVideoNode) { @@ -125,6 +149,7 @@ } #pragma mark - ASVideoNodeDelegate + - (void)videoNode:(ASVideoNode *)videoNode willChangePlayerState:(ASVideoNodePlayerState)state toState:(ASVideoNodePlayerState)toSate { //Ignore nicCageVideo From 253692df65caf0d767ba4e98c6ee6a11d6790396 Mon Sep 17 00:00:00 2001 From: Adlai Holler Date: Fri, 6 May 2016 21:45:31 -0700 Subject: [PATCH 07/52] [ASMultiplexImageNode] Do not request already-loaded images from data source to avoid loop --- AsyncDisplayKit/ASMultiplexImageNode.mm | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/AsyncDisplayKit/ASMultiplexImageNode.mm b/AsyncDisplayKit/ASMultiplexImageNode.mm index cb83bb1156..2af4f1836e 100644 --- a/AsyncDisplayKit/ASMultiplexImageNode.mm +++ b/AsyncDisplayKit/ASMultiplexImageNode.mm @@ -436,8 +436,12 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent } // Grab the best available image from the data source. + UIImage *existingImage = self.image; for (id imageIdentifier in _imageIdentifiers) { - UIImage *image = [_dataSource multiplexImageNode:self imageForImageIdentifier:imageIdentifier]; + // If this image is already loaded, don't request it from the data source again because + // the data source may generate a new instance of UIImage that returns NO for isEqual: + // and we'll end up in an infinite loading loop. + UIImage *image = ASObjectIsEqual(imageIdentifier, _loadedImageIdentifier) ? existingImage : [_dataSource multiplexImageNode:self imageForImageIdentifier:imageIdentifier]; if (image) { if (imageIdentifierOut) { *imageIdentifierOut = imageIdentifier; From 9f75e9a8e00a28cff02d28641e8fecd6b3703052 Mon Sep 17 00:00:00 2001 From: Hannah Troisi Date: Sat, 7 May 2016 01:20:13 -0700 Subject: [PATCH 08/52] [README.md] Removing Slack badge to save server time Will re-add once we have we have unlimited server time (paid Heroku account or deployed on our own server). --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index d916239814..b1e0f3f201 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,6 @@ [![Apps Using](https://img.shields.io/badge/Apps%20Using%20ASDK-%3E3,658-28B9FE.svg)](http://cocoapods.org/pods/AsyncDisplayKit) [![Downloads](https://img.shields.io/badge/Total%20Downloads-%3E377,749-28B9FE.svg)](http://cocoapods.org/pods/AsyncDisplayKit) -[![Slack Status](http://asdk-slack-auto-invite.herokuapp.com/badge.svg)](http://asdk-slack-auto-invite.herokuapp.com) [![Platform](https://img.shields.io/badge/platforms-iOS%20%7C%20tvOS-orange.svg)](http://AsyncDisplayKit.org) [![Languages](https://img.shields.io/badge/languages-ObjC%20%7C%20Swift-orange.svg)](http://AsyncDisplayKit.org) From fab117b8249991e1ac7dfe17b6a670dadcd706f5 Mon Sep 17 00:00:00 2001 From: Adlai Holler Date: Sat, 7 May 2016 15:14:30 -0700 Subject: [PATCH 09/52] [ASPINRemoteImageDownloader] Call download progress handler --- .../Details/ASPINRemoteImageDownloader.m | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/AsyncDisplayKit/Details/ASPINRemoteImageDownloader.m b/AsyncDisplayKit/Details/ASPINRemoteImageDownloader.m index 401211709c..2a11e70381 100644 --- a/AsyncDisplayKit/Details/ASPINRemoteImageDownloader.m +++ b/AsyncDisplayKit/Details/ASPINRemoteImageDownloader.m @@ -96,8 +96,9 @@ - (id )synchronouslyFetchedCachedImageWithURL:(NSURL *)URL; { - NSString *key = [[self sharedPINRemoteImageManager] cacheKeyForURL:URL processorKey:nil]; - PINRemoteImageManagerResult *result = [[self sharedPINRemoteImageManager] synchronousImageFromCacheWithCacheKey:key options:PINRemoteImageManagerDownloadOptionsSkipDecode]; + PINRemoteImageManager *manager = [self sharedPINRemoteImageManager]; + NSString *key = [manager cacheKeyForURL:URL processorKey:nil]; + PINRemoteImageManagerResult *result = [manager synchronousImageFromCacheWithCacheKey:key options:PINRemoteImageManagerDownloadOptionsSkipDecode]; #if PIN_ANIMATED_AVAILABLE if (result.alternativeRepresentation) { return result.alternativeRepresentation; @@ -133,7 +134,16 @@ downloadProgress:(ASImageDownloaderProgress)downloadProgress completion:(ASImageDownloaderCompletion)completion; { - return [[self sharedPINRemoteImageManager] downloadImageWithURL:URL options:PINRemoteImageManagerDownloadOptionsSkipDecode completion:^(PINRemoteImageManagerResult *result) { + return [[self sharedPINRemoteImageManager] downloadImageWithURL:URL options:PINRemoteImageManagerDownloadOptionsSkipDecode progressDownload:^(int64_t completedBytes, int64_t totalBytes) { + /// If we're targeting the main queue and we're on the main thread, complete immediately. + if (ASDisplayNodeThreadIsMain() && callbackQueue == dispatch_get_main_queue()) { + downloadProgress(totalBytes / (CGFloat)completedBytes); + } else { + dispatch_async(callbackQueue, ^{ + downloadProgress(totalBytes / (CGFloat)completedBytes); + }); + } + } completion:^(PINRemoteImageManagerResult * _Nonnull result) { /// If we're targeting the main queue and we're on the main thread, complete immediately. if (ASDisplayNodeThreadIsMain() && callbackQueue == dispatch_get_main_queue()) { #if PIN_ANIMATED_AVAILABLE From 654518b2b9d98182ce7fa228340c85b49fe40fc6 Mon Sep 17 00:00:00 2001 From: Adlai Holler Date: Sat, 7 May 2016 15:16:52 -0700 Subject: [PATCH 10/52] Fix nullability of ASMultiplexImageNode.imageManager --- AsyncDisplayKit/ASMultiplexImageNode.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AsyncDisplayKit/ASMultiplexImageNode.h b/AsyncDisplayKit/ASMultiplexImageNode.h index 73a74cbdeb..c81a402c5b 100644 --- a/AsyncDisplayKit/ASMultiplexImageNode.h +++ b/AsyncDisplayKit/ASMultiplexImageNode.h @@ -123,7 +123,7 @@ typedef NS_ENUM(NSUInteger, ASMultiplexImageNodeErrorCode) { * @see `+[NSURL URLWithAssetLocalIdentifier:targetSize:contentMode:options:]` below. */ -@property (nonatomic, strong) PHImageManager *imageManager; +@property (nullable, nonatomic, strong) PHImageManager *imageManager; #endif @end From 68e324d2d00edf3543d20551f2818a9dd7c2c505 Mon Sep 17 00:00:00 2001 From: Adlai Holler Date: Sat, 7 May 2016 15:18:11 -0700 Subject: [PATCH 11/52] Improve commentary --- AsyncDisplayKit/Details/ASPINRemoteImageDownloader.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AsyncDisplayKit/Details/ASPINRemoteImageDownloader.m b/AsyncDisplayKit/Details/ASPINRemoteImageDownloader.m index 2a11e70381..59a83afb80 100644 --- a/AsyncDisplayKit/Details/ASPINRemoteImageDownloader.m +++ b/AsyncDisplayKit/Details/ASPINRemoteImageDownloader.m @@ -135,7 +135,7 @@ completion:(ASImageDownloaderCompletion)completion; { return [[self sharedPINRemoteImageManager] downloadImageWithURL:URL options:PINRemoteImageManagerDownloadOptionsSkipDecode progressDownload:^(int64_t completedBytes, int64_t totalBytes) { - /// If we're targeting the main queue and we're on the main thread, complete immediately. + /// If we're targeting the main queue and we're on the main thread, call immediately. if (ASDisplayNodeThreadIsMain() && callbackQueue == dispatch_get_main_queue()) { downloadProgress(totalBytes / (CGFloat)completedBytes); } else { From 33d0919b1f5579c2af9556b079b95967d19652f0 Mon Sep 17 00:00:00 2001 From: Adlai Holler Date: Sat, 7 May 2016 15:50:03 -0700 Subject: [PATCH 12/52] [ASImageProtocols] Be smarter about nullability with image downloader protocol --- AsyncDisplayKit/Details/ASImageProtocols.h | 14 ++++++++++---- .../Details/ASPINRemoteImageDownloader.m | 2 ++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/AsyncDisplayKit/Details/ASImageProtocols.h b/AsyncDisplayKit/Details/ASImageProtocols.h index 6b86fb97db..ff6803bd8d 100644 --- a/AsyncDisplayKit/Details/ASImageProtocols.h +++ b/AsyncDisplayKit/Details/ASImageProtocols.h @@ -61,7 +61,16 @@ typedef void(^ASImageCacherCompletion)(id _Nullable i @end +/** + @param image The image that was downloaded, if the image could be successfully downloaded; nil otherwise. + @param error An error describing why the download of `URL` failed, if the download failed; nil otherwise. + @param downloadIdentifier The identifier for the download task that completed. + */ typedef void(^ASImageDownloaderCompletion)(id _Nullable image, NSError * _Nullable error, id _Nullable downloadIdentifier); + +/** + @param progress The progress of the download, in the range of (0.0, 1.0), inclusive. + */ typedef void(^ASImageDownloaderProgress)(CGFloat progress); typedef void(^ASImageDownloaderProgressImage)(UIImage *progressImage, CGFloat progress, id _Nullable downloadIdentifier); @@ -98,10 +107,7 @@ typedef NS_ENUM(NSUInteger, ASImageDownloaderPriority) { @param URL The URL of the image to download. @param callbackQueue The queue to call `downloadProgressBlock` and `completion` on. @param downloadProgress The block to be invoked when the download of `URL` progresses. - @param progress The progress of the download, in the range of (0.0, 1.0), inclusive. @param completion The block to be invoked when the download has completed, or has failed. - @param image The image that was downloaded, if the image could be successfully downloaded; nil otherwise. - @param error An error describing why the download of `URL` failed, if the download failed; nil otherwise. @discussion This method is likely to be called on the main thread, so any custom implementations should make sure to background any expensive download operations. @result An opaque identifier to be used in canceling the download, via `cancelImageDownloadForIdentifier:`. You must retain the identifier if you wish to use it later. @@ -109,7 +115,7 @@ typedef NS_ENUM(NSUInteger, ASImageDownloaderPriority) { - (nullable id)downloadImageWithURL:(NSURL *)URL callbackQueue:(dispatch_queue_t)callbackQueue downloadProgress:(nullable ASImageDownloaderProgress)downloadProgress - completion:(nullable ASImageDownloaderCompletion)completion; + completion:(ASImageDownloaderCompletion)completion; /** diff --git a/AsyncDisplayKit/Details/ASPINRemoteImageDownloader.m b/AsyncDisplayKit/Details/ASPINRemoteImageDownloader.m index 59a83afb80..ee78b0e7b6 100644 --- a/AsyncDisplayKit/Details/ASPINRemoteImageDownloader.m +++ b/AsyncDisplayKit/Details/ASPINRemoteImageDownloader.m @@ -135,6 +135,8 @@ completion:(ASImageDownloaderCompletion)completion; { return [[self sharedPINRemoteImageManager] downloadImageWithURL:URL options:PINRemoteImageManagerDownloadOptionsSkipDecode progressDownload:^(int64_t completedBytes, int64_t totalBytes) { + if (downloadProgress == nil) { return; } + /// If we're targeting the main queue and we're on the main thread, call immediately. if (ASDisplayNodeThreadIsMain() && callbackQueue == dispatch_get_main_queue()) { downloadProgress(totalBytes / (CGFloat)completedBytes); From 2e2ebe8c080a3b7ae5958b586576e6e02f2ea855 Mon Sep 17 00:00:00 2001 From: Adlai Holler Date: Sat, 7 May 2016 15:53:28 -0700 Subject: [PATCH 13/52] [ASPINRemoteImageDownloader] Replace instancetype with actual class name for shared instance --- AsyncDisplayKit/Details/ASPINRemoteImageDownloader.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AsyncDisplayKit/Details/ASPINRemoteImageDownloader.h b/AsyncDisplayKit/Details/ASPINRemoteImageDownloader.h index 12c6b27376..b76b298173 100644 --- a/AsyncDisplayKit/Details/ASPINRemoteImageDownloader.h +++ b/AsyncDisplayKit/Details/ASPINRemoteImageDownloader.h @@ -11,6 +11,6 @@ @interface ASPINRemoteImageDownloader : NSObject -+ (instancetype)sharedDownloader; ++ (ASPINRemoteImageDownloader *)sharedDownloader; @end From f9cd9730f77361e0078b17ca9c83b7fe009aaf14 Mon Sep 17 00:00:00 2001 From: Adlai Holler Date: Sat, 7 May 2016 15:55:00 -0700 Subject: [PATCH 14/52] Add nullability to ASPINRemoteImageDownloader.h --- AsyncDisplayKit/Details/ASPINRemoteImageDownloader.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/AsyncDisplayKit/Details/ASPINRemoteImageDownloader.h b/AsyncDisplayKit/Details/ASPINRemoteImageDownloader.h index b76b298173..a1238272ed 100644 --- a/AsyncDisplayKit/Details/ASPINRemoteImageDownloader.h +++ b/AsyncDisplayKit/Details/ASPINRemoteImageDownloader.h @@ -9,8 +9,12 @@ #import #import "ASImageProtocols.h" +NS_ASSUME_NONNULL_BEGIN + @interface ASPINRemoteImageDownloader : NSObject + (ASPINRemoteImageDownloader *)sharedDownloader; @end + +NS_ASSUME_NONNULL_END From c0eb6cac09cf819f864ab753585977f70bd70f5b Mon Sep 17 00:00:00 2001 From: Garrett Moon Date: Mon, 9 May 2016 15:00:44 -0700 Subject: [PATCH 15/52] Add support for disabling progressive image rendering Differential Revision: https://phabricator.pinadmin.com/D89742 --- AsyncDisplayKit/ASMultiplexImageNode.h | 6 ++ AsyncDisplayKit/ASMultiplexImageNode.mm | 79 +++++++++++++++++-------- AsyncDisplayKit/ASNetworkImageNode.h | 6 ++ AsyncDisplayKit/ASNetworkImageNode.mm | 27 ++++++++- 4 files changed, 92 insertions(+), 26 deletions(-) diff --git a/AsyncDisplayKit/ASMultiplexImageNode.h b/AsyncDisplayKit/ASMultiplexImageNode.h index 73a74cbdeb..0826cd951b 100644 --- a/AsyncDisplayKit/ASMultiplexImageNode.h +++ b/AsyncDisplayKit/ASMultiplexImageNode.h @@ -117,6 +117,12 @@ typedef NS_ENUM(NSUInteger, ASMultiplexImageNodeErrorCode) { */ @property (nullable, nonatomic, readonly) ASImageIdentifier displayedImageIdentifier; +/** + * @abstract If the downloader implements progressive image rendering and this value is YES progressive renders of the + * image will be displayed as the image downloads. Defaults to YES. + */ +@property (nonatomic, assign, readwrite) BOOL shouldRenderProgressImages; + #if TARGET_OS_IOS /** * @abstract The image manager that this image node should use when requesting images from the Photos framework. If this is `nil` (the default), then `PHImageManager.defaultManager` is used. diff --git a/AsyncDisplayKit/ASMultiplexImageNode.mm b/AsyncDisplayKit/ASMultiplexImageNode.mm index cb83bb1156..e5d6e47fbe 100644 --- a/AsyncDisplayKit/ASMultiplexImageNode.mm +++ b/AsyncDisplayKit/ASMultiplexImageNode.mm @@ -85,6 +85,10 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent ASDN::RecursiveMutex _downloadIdentifierLock; id _downloadIdentifier; + // Properties + ASDN::RecursiveMutex _propertyLock; + BOOL _shouldRenderProgressImages; + //set on init only BOOL _downloaderSupportsNewProtocol; BOOL _downloaderImplementsSetProgress; @@ -186,6 +190,8 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent _cacheSupportsNewProtocol = [cache respondsToSelector:@selector(cachedImageWithURL:callbackQueue:completion:)]; _cacheSupportsClearing = [cache respondsToSelector:@selector(clearFetchedImageFromCacheWithURL:)]; + _shouldRenderProgressImages = YES; + self.shouldBypassEnsureDisplay = YES; return self; @@ -339,6 +345,27 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent #endif } + +- (void)setShouldRenderProgressImages:(BOOL)shouldRenderProgressImages +{ + ASDN::MutexLocker l(_propertyLock); + if (shouldRenderProgressImages == _shouldRenderProgressImages) { + return; + } + + _shouldRenderProgressImages = shouldRenderProgressImages; + + + ASDN::MutexUnlocker u(_propertyLock); + [self _updateProgressImageBlockOnDownloaderIfNeeded]; +} + +- (BOOL)shouldRenderProgressImages +{ + ASDN::MutexLocker l(_propertyLock); + return _shouldRenderProgressImages; +} + #pragma mark - #pragma mark - @@ -458,32 +485,34 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent */ - (void)_updateProgressImageBlockOnDownloaderIfNeeded { - // Read our interface state before locking so that we don't lock super while holding our lock. - ASInterfaceState interfaceState = self.interfaceState; - ASDN::MutexLocker l(_downloadIdentifierLock); - - if (!_downloaderImplementsSetProgress || _downloadIdentifier == nil) { + BOOL shouldRenderProgressImages = self.shouldRenderProgressImages; + + // Read our interface state before locking so that we don't lock super while holding our lock. + ASInterfaceState interfaceState = self.interfaceState; + ASDN::MutexLocker l(_downloadIdentifierLock); + + if (!_downloaderImplementsSetProgress || _downloadIdentifier == nil) { + return; + } + + ASImageDownloaderProgressImage progress = nil; + if (shouldRenderProgressImages && ASInterfaceStateIncludesVisible(interfaceState)) { + __weak __typeof__(self) weakSelf = self; + progress = ^(UIImage * _Nonnull progressImage, CGFloat progress, id _Nullable downloadIdentifier) { + __typeof__(self) strongSelf = weakSelf; + if (strongSelf == nil) { return; - } - - ASImageDownloaderProgressImage progress = nil; - if (ASInterfaceStateIncludesVisible(interfaceState)) { - __weak __typeof__(self) weakSelf = self; - progress = ^(UIImage * _Nonnull progressImage, CGFloat progress, id _Nullable downloadIdentifier) { - __typeof__(self) strongSelf = weakSelf; - if (strongSelf == nil) { - return; - } - - ASDN::MutexLocker l(strongSelf->_downloadIdentifierLock); - //Getting a result back for a different download identifier, download must not have been successfully canceled - if (ASObjectIsEqual(strongSelf->_downloadIdentifier, downloadIdentifier) == NO && downloadIdentifier != nil) { - return; - } - strongSelf.image = progressImage; - }; - } - [_downloader setProgressImageBlock:progress callbackQueue:dispatch_get_main_queue() withDownloadIdentifier:_downloadIdentifier]; + } + + ASDN::MutexLocker l(strongSelf->_downloadIdentifierLock); + //Getting a result back for a different download identifier, download must not have been successfully canceled + if (ASObjectIsEqual(strongSelf->_downloadIdentifier, downloadIdentifier) == NO && downloadIdentifier != nil) { + return; + } + strongSelf.image = progressImage; + }; + } + [_downloader setProgressImageBlock:progress callbackQueue:dispatch_get_main_queue() withDownloadIdentifier:_downloadIdentifier]; } - (void)_clearImage diff --git a/AsyncDisplayKit/ASNetworkImageNode.h b/AsyncDisplayKit/ASNetworkImageNode.h index ef3feba1e1..abbc800840 100644 --- a/AsyncDisplayKit/ASNetworkImageNode.h +++ b/AsyncDisplayKit/ASNetworkImageNode.h @@ -73,6 +73,12 @@ NS_ASSUME_NONNULL_BEGIN */ @property (nonatomic, assign, readwrite) BOOL shouldCacheImage; +/** + * If the downloader implements progressive image rendering and this value is YES progressive renders of the + * image will be displayed as the image downloads. Defaults to YES. + */ +@property (nonatomic, assign, readwrite) BOOL shouldRenderProgressImages; + /** * The image quality of the current image. This is a number between 0 and 1 and can be used to track * progressive progress. Calculated by dividing number of bytes / expected number of total bytes. diff --git a/AsyncDisplayKit/ASNetworkImageNode.mm b/AsyncDisplayKit/ASNetworkImageNode.mm index 27a677fe61..c52e01304d 100755 --- a/AsyncDisplayKit/ASNetworkImageNode.mm +++ b/AsyncDisplayKit/ASNetworkImageNode.mm @@ -45,6 +45,8 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0}; BOOL _delegateSupportsDidStartFetchingData; BOOL _delegateSupportsDidFailWithError; BOOL _delegateSupportsImageNodeDidFinishDecoding; + + BOOL _shouldRenderProgressImages; //set on init only BOOL _downloaderSupportsNewProtocol; @@ -83,6 +85,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0}; _cacheSupportsSynchronousFetch = [cache respondsToSelector:@selector(synchronouslyFetchedCachedImageWithURL:)]; _shouldCacheImage = YES; + _shouldRenderProgressImages = YES; self.shouldBypassEnsureDisplay = YES; return self; @@ -218,6 +221,26 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0}; return _delegate; } +- (void)setShouldRenderProgressImages:(BOOL)shouldRenderProgressImages +{ + ASDN::MutexLocker l(_lock); + if (shouldRenderProgressImages == _shouldRenderProgressImages) { + return; + } + + _shouldRenderProgressImages = shouldRenderProgressImages; + + + ASDN::MutexUnlocker u(_lock); + [self _updateProgressImageBlockOnDownloaderIfNeeded]; +} + +- (BOOL)shouldRenderProgressImages +{ + ASDN::MutexLocker l(_lock); + return _shouldRenderProgressImages; +} + - (BOOL)placeholderShouldPersist { ASDN::MutexLocker l(_lock); @@ -309,6 +332,8 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0}; */ - (void)_updateProgressImageBlockOnDownloaderIfNeeded { + BOOL shouldRenderProgressImages = self.shouldRenderProgressImages; + // Read our interface state before locking so that we don't lock super while holding our lock. ASInterfaceState interfaceState = self.interfaceState; ASDN::MutexLocker l(_lock); @@ -318,7 +343,7 @@ static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0}; } ASImageDownloaderProgressImage progress = nil; - if (ASInterfaceStateIncludesVisible(interfaceState)) { + if (shouldRenderProgressImages && ASInterfaceStateIncludesVisible(interfaceState)) { __weak __typeof__(self) weakSelf = self; progress = ^(UIImage * _Nonnull progressImage, CGFloat progress, id _Nullable downloadIdentifier) { __typeof__(self) strongSelf = weakSelf; From 082ababda67d69d8c00947e7adcb9fb5ecf48d8e Mon Sep 17 00:00:00 2001 From: rcancro Date: Mon, 9 May 2016 15:57:29 -0700 Subject: [PATCH 16/52] Fix to text shrinking Summary: Previously the first thing we did when calculating the size of text was to truncate it. This could lead to ASFontSizeAdjuster being sent a truncated string which, obviously, never needed to shrink. If we change the order then we first shrink, then truncate if still necessary. Reviewers: scottg, levi, garrett Differential Revision: https://phabricator.pinadmin.com/D89780 --- AsyncDisplayKit/TextKit/ASTextKitRenderer.mm | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/AsyncDisplayKit/TextKit/ASTextKitRenderer.mm b/AsyncDisplayKit/TextKit/ASTextKitRenderer.mm index bc7d2c1069..035db7977f 100755 --- a/AsyncDisplayKit/TextKit/ASTextKitRenderer.mm +++ b/AsyncDisplayKit/TextKit/ASTextKitRenderer.mm @@ -137,25 +137,30 @@ static NSCharacterSet *_defaultAvoidTruncationCharacterSet() - (void)_calculateSize { - [self truncater]; // if we have no scale factors or an unconstrained width, there is no reason to try to adjust the font size if (isinf(_constrainedSize.width) == NO && [_attributes.pointSizeScaleFactors count] > 0) { _currentScaleFactor = [[self fontSizeAdjuster] scaleFactor]; } - // Force glyph generation and layout, which may not have happened yet (and isn't triggered by - // -usedRectForTextContainer:). __block NSTextStorage *scaledTextStorage = nil; BOOL isScaled = [self isScaled]; - [[self context] performBlockWithLockedTextKitComponents:^(NSLayoutManager *layoutManager, NSTextStorage *textStorage, NSTextContainer *textContainer) { - if (isScaled) { + if (isScaled) { + // apply the string scale before truncating or else we may truncate the string after we've done the work to shrink it. + [[self context] performBlockWithLockedTextKitComponents:^(NSLayoutManager *layoutManager, NSTextStorage *textStorage, NSTextContainer *textContainer) { NSMutableAttributedString *scaledString = [[NSMutableAttributedString alloc] initWithAttributedString:textStorage]; [ASTextKitFontSizeAdjuster adjustFontSizeForAttributeString:scaledString withScaleFactor:_currentScaleFactor]; scaledTextStorage = [[NSTextStorage alloc] initWithAttributedString:scaledString]; [textStorage removeLayoutManager:layoutManager]; [scaledTextStorage addLayoutManager:layoutManager]; - } + }]; + } + + [self truncater]; + + // Force glyph generation and layout, which may not have happened yet (and isn't triggered by + // -usedRectForTextContainer:). + [[self context] performBlockWithLockedTextKitComponents:^(NSLayoutManager *layoutManager, NSTextStorage *textStorage, NSTextContainer *textContainer) { [layoutManager ensureLayoutForTextContainer:textContainer]; }]; From 22e026a5e1bc015c3dfc5195ed5fdb44f070c504 Mon Sep 17 00:00:00 2001 From: rcancro Date: Mon, 9 May 2016 16:36:27 -0700 Subject: [PATCH 17/52] fix truncater method to only return the truncater. --- AsyncDisplayKit/TextKit/ASTextKitRenderer.mm | 2 +- AsyncDisplayKit/TextKit/ASTextKitTailTruncater.mm | 4 +--- AsyncDisplayKit/TextKit/ASTextKitTruncating.h | 5 +++++ AsyncDisplayKitTests/ASTextKitTruncationTests.mm | 11 ++++++----- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/AsyncDisplayKit/TextKit/ASTextKitRenderer.mm b/AsyncDisplayKit/TextKit/ASTextKitRenderer.mm index 035db7977f..4d3c7c3ef9 100755 --- a/AsyncDisplayKit/TextKit/ASTextKitRenderer.mm +++ b/AsyncDisplayKit/TextKit/ASTextKitRenderer.mm @@ -156,7 +156,7 @@ static NSCharacterSet *_defaultAvoidTruncationCharacterSet() }]; } - [self truncater]; + [[self truncater] truncate]; // Force glyph generation and layout, which may not have happened yet (and isn't triggered by // -usedRectForTextContainer:). diff --git a/AsyncDisplayKit/TextKit/ASTextKitTailTruncater.mm b/AsyncDisplayKit/TextKit/ASTextKitTailTruncater.mm index d48013a772..7f77c3d76a 100755 --- a/AsyncDisplayKit/TextKit/ASTextKitTailTruncater.mm +++ b/AsyncDisplayKit/TextKit/ASTextKitTailTruncater.mm @@ -30,8 +30,6 @@ _context = context; _truncationAttributedString = truncationAttributedString; _avoidTailTruncationSet = avoidTailTruncationSet; - - [self _truncate]; } return self; } @@ -153,7 +151,7 @@ } } -- (void)_truncate +- (void)truncate { [_context performBlockWithLockedTextKitComponents:^(NSLayoutManager *layoutManager, NSTextStorage *textStorage, NSTextContainer *textContainer) { NSUInteger originalStringLength = textStorage.length; diff --git a/AsyncDisplayKit/TextKit/ASTextKitTruncating.h b/AsyncDisplayKit/TextKit/ASTextKitTruncating.h index 946c378f36..91f79c0740 100755 --- a/AsyncDisplayKit/TextKit/ASTextKitTruncating.h +++ b/AsyncDisplayKit/TextKit/ASTextKitTruncating.h @@ -33,4 +33,9 @@ truncationAttributedString:(NSAttributedString *)truncationAttributedString avoidTailTruncationSet:(NSCharacterSet *)avoidTailTruncationSet; +/** + * Actually do the truncation. + */ +- (void)truncate; + @end diff --git a/AsyncDisplayKitTests/ASTextKitTruncationTests.mm b/AsyncDisplayKitTests/ASTextKitTruncationTests.mm index d82ae0fd2d..dab6b240e7 100644 --- a/AsyncDisplayKitTests/ASTextKitTruncationTests.mm +++ b/AsyncDisplayKitTests/ASTextKitTruncationTests.mm @@ -53,6 +53,7 @@ ASTextKitTailTruncater *tailTruncater = [[ASTextKitTailTruncater alloc] initWithContext:context truncationAttributedString:nil avoidTailTruncationSet:nil]; + [tailTruncater truncate]; XCTAssert(NSEqualRanges(textKitVisibleRange, tailTruncater.visibleRanges[0])); } @@ -71,6 +72,7 @@ ASTextKitTailTruncater *tailTruncater = [[ASTextKitTailTruncater alloc] initWithContext:context truncationAttributedString:[self _simpleTruncationAttributedString] avoidTailTruncationSet:[NSCharacterSet characterSetWithCharactersInString:@""]]; + [tailTruncater truncate]; __block NSString *drawnString; [context performBlockWithLockedTextKitComponents:^(NSLayoutManager *layoutManager, NSTextStorage *textStorage, NSTextContainer *textContainer) { drawnString = textStorage.string; @@ -95,7 +97,7 @@ ASTextKitTailTruncater *tailTruncater = [[ASTextKitTailTruncater alloc] initWithContext:context truncationAttributedString:[self _simpleTruncationAttributedString] avoidTailTruncationSet:[NSCharacterSet characterSetWithCharactersInString:@"."]]; - (void)tailTruncater; + [tailTruncater truncate]; __block NSString *drawnString; [context performBlockWithLockedTextKitComponents:^(NSLayoutManager *layoutManager, NSTextStorage *textStorage, NSTextContainer *textContainer) { drawnString = textStorage.string; @@ -120,8 +122,7 @@ ASTextKitTailTruncater *tailTruncater = [[ASTextKitTailTruncater alloc] initWithContext:context truncationAttributedString:[self _simpleTruncationAttributedString] avoidTailTruncationSet:[NSCharacterSet characterSetWithCharactersInString:@"."]]; - // So Xcode doesn't yell at me for an unused var... - (void)tailTruncater; + [tailTruncater truncate]; __block NSString *drawnString; [context performBlockWithLockedTextKitComponents:^(NSLayoutManager *layoutManager, NSTextStorage *textStorage, NSTextContainer *textContainer) { drawnString = textStorage.string; @@ -144,9 +145,9 @@ layoutManagerDelegate:nil textStorageCreationBlock:nil]; - XCTAssertNoThrow([[ASTextKitTailTruncater alloc] initWithContext:context + XCTAssertNoThrow([[[ASTextKitTailTruncater alloc] initWithContext:context truncationAttributedString:[self _simpleTruncationAttributedString] - avoidTailTruncationSet:[NSCharacterSet characterSetWithCharactersInString:@"."]]); + avoidTailTruncationSet:[NSCharacterSet characterSetWithCharactersInString:@"."]] truncate]); } @end From 36ce9527de44324396c4884c6f181dc381eb1f6f Mon Sep 17 00:00:00 2001 From: Garrett Moon Date: Mon, 9 May 2016 17:20:06 -0700 Subject: [PATCH 18/52] Update comments --- AsyncDisplayKit/ASMultiplexImageNode.h | 3 ++- AsyncDisplayKit/ASNetworkImageNode.h | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/AsyncDisplayKit/ASMultiplexImageNode.h b/AsyncDisplayKit/ASMultiplexImageNode.h index 0826cd951b..eb01209dfd 100644 --- a/AsyncDisplayKit/ASMultiplexImageNode.h +++ b/AsyncDisplayKit/ASMultiplexImageNode.h @@ -119,7 +119,8 @@ typedef NS_ENUM(NSUInteger, ASMultiplexImageNodeErrorCode) { /** * @abstract If the downloader implements progressive image rendering and this value is YES progressive renders of the - * image will be displayed as the image downloads. Defaults to YES. + * image will be displayed as the image downloads. Regardless of this properties value, progress renders will + * only occur when the node is visible. Defaults to YES. */ @property (nonatomic, assign, readwrite) BOOL shouldRenderProgressImages; diff --git a/AsyncDisplayKit/ASNetworkImageNode.h b/AsyncDisplayKit/ASNetworkImageNode.h index abbc800840..d2aadfe854 100644 --- a/AsyncDisplayKit/ASNetworkImageNode.h +++ b/AsyncDisplayKit/ASNetworkImageNode.h @@ -75,7 +75,8 @@ NS_ASSUME_NONNULL_BEGIN /** * If the downloader implements progressive image rendering and this value is YES progressive renders of the - * image will be displayed as the image downloads. Defaults to YES. + * image will be displayed as the image downloads. Regardless of this properties value, progress renders will + * only occur when the node is visible. Defaults to YES. */ @property (nonatomic, assign, readwrite) BOOL shouldRenderProgressImages; From 8bb4eba08079bcbf11f21fefaa69166d297ea40b Mon Sep 17 00:00:00 2001 From: rcancro Date: Mon, 25 Apr 2016 16:59:00 -0700 Subject: [PATCH 19/52] Initial attempt at implementing Display Traits Initial attempt to get display traits working with ASEnvironment. To get proper ASDisplayTraits support, you must use an ASViewController. The ASViewController implements UITraitCollection-related methods (`traitCollectionDidChange:`, `willTransitionToTraitCollection:withTransitionCoordinator:`, viewWillTransitionToSize:withTransitionCoordinator`) to update the internal ASDisplayTraits and propagate them to subnodes. ASTableNode and ASCollectionNode don't actually have their cells as subnodes, so a little bit of trickery is involved (on `setEnvironment:` the table/collection node gets its data controllers completedNodes and propagates the new traits. see `ASDisplayTraitsCollectionTableSetEnvironmentState`). The data controller also passes the current display traits when creating new cells. ASViewController also supports the ability to return a custom set of display traits. So if you have a modal dialog that should always be told it is in a compact size class, you can set the override block before displaying the VC. A new example, called Display Traits, has been added. It shows how display traits can be used in a ASViewController with a normal ASDisplayNode as its root, as well as in ASViewControllers hosting table nodes and collection nodes. There is also an example of overriding the default display traits of a VC. Please provide feedback! --- AsyncDisplayKit.xcodeproj/project.pbxproj | 30 +- AsyncDisplayKit/ASCollectionNode.mm | 3 + AsyncDisplayKit/ASCollectionView.mm | 11 +- AsyncDisplayKit/ASDisplayNode.mm | 9 +- .../{ASTableNode.m => ASTableNode.mm} | 3 + AsyncDisplayKit/ASTableView.mm | 14 +- AsyncDisplayKit/ASViewController.h | 15 + ...ASViewController.m => ASViewController.mm} | 73 +++- AsyncDisplayKit/Details/ASDataController.h | 11 + AsyncDisplayKit/Details/ASDataController.mm | 12 +- AsyncDisplayKit/Details/ASEnvironment.h | 64 ++- AsyncDisplayKit/Details/ASEnvironment.m | 33 -- AsyncDisplayKit/Details/ASEnvironment.mm | 77 ++++ AsyncDisplayKit/Layout/ASLayoutSpec.mm | 11 +- AsyncDisplayKit/Layout/ASLayoutablePrivate.h | 2 +- .../Private/ASEnvironmentInternal.h | 7 +- .../Private/ASEnvironmentInternal.mm | 38 +- examples/DisplayTraits/Podfile | 3 + .../Sample.xcodeproj/project.pbxproj | 379 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/xcschemes/Sample.xcscheme | 88 ++++ .../contents.xcworkspacedata | 10 + examples/DisplayTraits/Sample/AppDelegate.h | 20 + examples/DisplayTraits/Sample/AppDelegate.m | 31 ++ .../Sample/CollectionViewController.h | 15 + .../Sample/CollectionViewController.m | 72 ++++ examples/DisplayTraits/Sample/Info.plist | 39 ++ examples/DisplayTraits/Sample/KittenNode.h | 23 ++ examples/DisplayTraits/Sample/KittenNode.m | 170 ++++++++ .../Sample/Launch Screen.storyboard | 50 +++ .../Sample/OverrideViewController.h | 29 ++ .../Sample/OverrideViewController.m | 95 +++++ .../Sample/TableViewController.h | 16 + .../Sample/TableViewController.m | 62 +++ .../DisplayTraits/Sample/ViewController.h | 16 + .../DisplayTraits/Sample/ViewController.m | 45 +++ examples/DisplayTraits/Sample/main.m | 20 + 37 files changed, 1535 insertions(+), 68 deletions(-) rename AsyncDisplayKit/{ASTableNode.m => ASTableNode.mm} (97%) rename AsyncDisplayKit/{ASViewController.m => ASViewController.mm} (59%) delete mode 100644 AsyncDisplayKit/Details/ASEnvironment.m create mode 100644 AsyncDisplayKit/Details/ASEnvironment.mm create mode 100644 examples/DisplayTraits/Podfile create mode 100644 examples/DisplayTraits/Sample.xcodeproj/project.pbxproj create mode 100644 examples/DisplayTraits/Sample.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 examples/DisplayTraits/Sample.xcodeproj/xcshareddata/xcschemes/Sample.xcscheme create mode 100644 examples/DisplayTraits/Sample.xcworkspace/contents.xcworkspacedata create mode 100644 examples/DisplayTraits/Sample/AppDelegate.h create mode 100644 examples/DisplayTraits/Sample/AppDelegate.m create mode 100644 examples/DisplayTraits/Sample/CollectionViewController.h create mode 100644 examples/DisplayTraits/Sample/CollectionViewController.m create mode 100644 examples/DisplayTraits/Sample/Info.plist create mode 100644 examples/DisplayTraits/Sample/KittenNode.h create mode 100644 examples/DisplayTraits/Sample/KittenNode.m create mode 100644 examples/DisplayTraits/Sample/Launch Screen.storyboard create mode 100644 examples/DisplayTraits/Sample/OverrideViewController.h create mode 100644 examples/DisplayTraits/Sample/OverrideViewController.m create mode 100644 examples/DisplayTraits/Sample/TableViewController.h create mode 100644 examples/DisplayTraits/Sample/TableViewController.m create mode 100644 examples/DisplayTraits/Sample/ViewController.h create mode 100644 examples/DisplayTraits/Sample/ViewController.m create mode 100644 examples/DisplayTraits/Sample/main.m diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index 8d5e02ea5d..7c880f867d 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -190,7 +190,6 @@ 25E327581C16819500A2170C /* ASPagerNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 25E327551C16819500A2170C /* ASPagerNode.m */; }; 25E327591C16819500A2170C /* ASPagerNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 25E327551C16819500A2170C /* ASPagerNode.m */; }; 2767E9411BB19BD600EA9B77 /* ASViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = ACC945A81BA9E7A0005E1FB8 /* ASViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 2767E9421BB19BD600EA9B77 /* ASViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = ACC945AA1BA9E7C1005E1FB8 /* ASViewController.m */; }; 2911485C1A77147A005D0878 /* ASControlNodeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2911485B1A77147A005D0878 /* ASControlNodeTests.m */; }; 291B63FB1AA53A7A000A71B3 /* ASScrollDirection.h in Headers */ = {isa = PBXBuildFile; fileRef = 296A0A311A951715005ACEAA /* ASScrollDirection.h */; settings = {ATTRIBUTES = (Public, ); }; }; 292C599F1A956527007E5DD6 /* ASLayoutRangeType.h in Headers */ = {isa = PBXBuildFile; fileRef = 292C59991A956527007E5DD6 /* ASLayoutRangeType.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -275,8 +274,6 @@ 68EE0DC01C1B4ED300BA1B99 /* ASMainSerialQueue.mm in Sources */ = {isa = PBXBuildFile; fileRef = 68EE0DBC1C1B4ED300BA1B99 /* ASMainSerialQueue.mm */; }; 698548631CA9E025008A345F /* ASEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = 698548611CA9E025008A345F /* ASEnvironment.h */; settings = {ATTRIBUTES = (Public, ); }; }; 698548641CA9E025008A345F /* ASEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = 698548611CA9E025008A345F /* ASEnvironment.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 698548651CA9E025008A345F /* ASEnvironment.m in Sources */ = {isa = PBXBuildFile; fileRef = 698548621CA9E025008A345F /* ASEnvironment.m */; }; - 698548661CA9E025008A345F /* ASEnvironment.m in Sources */ = {isa = PBXBuildFile; fileRef = 698548621CA9E025008A345F /* ASEnvironment.m */; }; 698C8B611CAB49FC0052DC3F /* ASLayoutableExtensibility.h in Headers */ = {isa = PBXBuildFile; fileRef = 698C8B601CAB49FC0052DC3F /* ASLayoutableExtensibility.h */; settings = {ATTRIBUTES = (Public, ); }; }; 698C8B621CAB49FC0052DC3F /* ASLayoutableExtensibility.h in Headers */ = {isa = PBXBuildFile; fileRef = 698C8B601CAB49FC0052DC3F /* ASLayoutableExtensibility.h */; settings = {ATTRIBUTES = (Public, ); }; }; 69CB62AB1CB8165900024920 /* _ASDisplayViewAccessiblity.h in Headers */ = {isa = PBXBuildFile; fileRef = 69CB62A91CB8165900024920 /* _ASDisplayViewAccessiblity.h */; }; @@ -336,6 +333,9 @@ 9C8898BD1C738BB800D6B02E /* ASTextKitFontSizeAdjuster.h in Headers */ = {isa = PBXBuildFile; fileRef = A32FEDD31C501B6A004F642A /* ASTextKitFontSizeAdjuster.h */; }; 9CDC18CC1B910E12004965E2 /* ASLayoutablePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 9CDC18CB1B910E12004965E2 /* ASLayoutablePrivate.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9CDC18CD1B910E12004965E2 /* ASLayoutablePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 9CDC18CB1B910E12004965E2 /* ASLayoutablePrivate.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9CFFC6BE1CCAC52B006A6476 /* ASEnvironment.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9CFFC6BD1CCAC52B006A6476 /* ASEnvironment.mm */; }; + 9CFFC6C01CCAC73C006A6476 /* ASViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9CFFC6BF1CCAC73C006A6476 /* ASViewController.mm */; }; + 9CFFC6C21CCAC768006A6476 /* ASTableNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9CFFC6C11CCAC768006A6476 /* ASTableNode.mm */; }; 9F06E5CD1B4CAF4200F015D8 /* ASCollectionViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 9F06E5CC1B4CAF4200F015D8 /* ASCollectionViewTests.m */; }; A2763D791CBDD57D00A9ADBD /* ASPINRemoteImageDownloader.h in Headers */ = {isa = PBXBuildFile; fileRef = A2763D771CBDD57D00A9ADBD /* ASPINRemoteImageDownloader.h */; }; A2763D7A1CBDD57D00A9ADBD /* ASPINRemoteImageDownloader.h in Headers */ = {isa = PBXBuildFile; fileRef = A2763D771CBDD57D00A9ADBD /* ASPINRemoteImageDownloader.h */; }; @@ -362,7 +362,6 @@ AC7A2C171BDE11DF0093FE1A /* ASTableViewInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = AC7A2C161BDE11DF0093FE1A /* ASTableViewInternal.h */; }; AC7A2C181BDE11DF0093FE1A /* ASTableViewInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = AC7A2C161BDE11DF0093FE1A /* ASTableViewInternal.h */; }; ACC945A91BA9E7A0005E1FB8 /* ASViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = ACC945A81BA9E7A0005E1FB8 /* ASViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; - ACC945AB1BA9E7C1005E1FB8 /* ASViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = ACC945AA1BA9E7C1005E1FB8 /* ASViewController.m */; }; ACF6ED1A1B17843500DA7C62 /* ASBackgroundLayoutSpec.h in Headers */ = {isa = PBXBuildFile; fileRef = ACF6ED011B17843500DA7C62 /* ASBackgroundLayoutSpec.h */; settings = {ATTRIBUTES = (Public, ); }; }; ACF6ED1B1B17843500DA7C62 /* ASBackgroundLayoutSpec.mm in Sources */ = {isa = PBXBuildFile; fileRef = ACF6ED021B17843500DA7C62 /* ASBackgroundLayoutSpec.mm */; }; ACF6ED1C1B17843500DA7C62 /* ASCenterLayoutSpec.h in Headers */ = {isa = PBXBuildFile; fileRef = ACF6ED031B17843500DA7C62 /* ASCenterLayoutSpec.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -405,7 +404,6 @@ AEEC47E21C20C2DD00EC1693 /* ASVideoNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = AEEC47E01C20C2DD00EC1693 /* ASVideoNode.mm */; }; AEEC47E41C21D3D200EC1693 /* ASVideoNodeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = AEEC47E31C21D3D200EC1693 /* ASVideoNodeTests.m */; }; B0F8805A1BEAEC7500D17647 /* ASTableNode.h in Headers */ = {isa = PBXBuildFile; fileRef = B0F880581BEAEC7500D17647 /* ASTableNode.h */; settings = {ATTRIBUTES = (Public, ); }; }; - B0F8805B1BEAEC7500D17647 /* ASTableNode.m in Sources */ = {isa = PBXBuildFile; fileRef = B0F880591BEAEC7500D17647 /* ASTableNode.m */; }; B13CA0F71C519E9400E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = B13CA0F61C519E9400E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; B13CA0F81C519EBA00E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = B13CA0F61C519E9400E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; B13CA1001C52004900E031AB /* ASCollectionNode+Beta.h in Headers */ = {isa = PBXBuildFile; fileRef = B13CA0FF1C52004900E031AB /* ASCollectionNode+Beta.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -499,7 +497,6 @@ B350625D1B0111740018CF92 /* Photos.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 051943141A1575670030A7D0 /* Photos.framework */; }; B350625E1B0111780018CF92 /* AssetsLibrary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 051943121A1575630030A7D0 /* AssetsLibrary.framework */; }; B350625F1B0111800018CF92 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 058D09AF195D04C000B7D73C /* Foundation.framework */; }; - C78F7E2A1BF7808300CDEAFC /* ASTableNode.m in Sources */ = {isa = PBXBuildFile; fileRef = B0F880591BEAEC7500D17647 /* ASTableNode.m */; }; C78F7E2B1BF7809800CDEAFC /* ASTableNode.h in Headers */ = {isa = PBXBuildFile; fileRef = B0F880581BEAEC7500D17647 /* ASTableNode.h */; settings = {ATTRIBUTES = (Public, ); }; }; CC3B20831C3F76D600798563 /* ASPendingStateController.h in Headers */ = {isa = PBXBuildFile; fileRef = CC3B20811C3F76D600798563 /* ASPendingStateController.h */; }; CC3B20841C3F76D600798563 /* ASPendingStateController.h in Headers */ = {isa = PBXBuildFile; fileRef = CC3B20811C3F76D600798563 /* ASPendingStateController.h */; }; @@ -779,7 +776,6 @@ 68EE0DBB1C1B4ED300BA1B99 /* ASMainSerialQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASMainSerialQueue.h; sourceTree = ""; }; 68EE0DBC1C1B4ED300BA1B99 /* ASMainSerialQueue.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASMainSerialQueue.mm; sourceTree = ""; }; 698548611CA9E025008A345F /* ASEnvironment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASEnvironment.h; sourceTree = ""; }; - 698548621CA9E025008A345F /* ASEnvironment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASEnvironment.m; sourceTree = ""; }; 698C8B601CAB49FC0052DC3F /* ASLayoutableExtensibility.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASLayoutableExtensibility.h; path = AsyncDisplayKit/Layout/ASLayoutableExtensibility.h; sourceTree = ""; }; 69CB62A91CB8165900024920 /* _ASDisplayViewAccessiblity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _ASDisplayViewAccessiblity.h; sourceTree = ""; }; 69CB62AA1CB8165900024920 /* _ASDisplayViewAccessiblity.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = _ASDisplayViewAccessiblity.mm; sourceTree = ""; }; @@ -809,6 +805,9 @@ 9C8221941BA237B80037F19A /* ASStackBaselinePositionedLayout.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASStackBaselinePositionedLayout.mm; sourceTree = ""; }; 9C8898BA1C738B9800D6B02E /* ASTextKitFontSizeAdjuster.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ASTextKitFontSizeAdjuster.mm; path = TextKit/ASTextKitFontSizeAdjuster.mm; sourceTree = ""; }; 9CDC18CB1B910E12004965E2 /* ASLayoutablePrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASLayoutablePrivate.h; path = AsyncDisplayKit/Layout/ASLayoutablePrivate.h; sourceTree = ""; }; + 9CFFC6BD1CCAC52B006A6476 /* ASEnvironment.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASEnvironment.mm; sourceTree = ""; }; + 9CFFC6BF1CCAC73C006A6476 /* ASViewController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASViewController.mm; sourceTree = ""; }; + 9CFFC6C11CCAC768006A6476 /* ASTableNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASTableNode.mm; sourceTree = ""; }; 9F06E5CC1B4CAF4200F015D8 /* ASCollectionViewTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = ASCollectionViewTests.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; A2763D771CBDD57D00A9ADBD /* ASPINRemoteImageDownloader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASPINRemoteImageDownloader.h; path = Details/ASPINRemoteImageDownloader.h; sourceTree = ""; }; A2763D781CBDD57D00A9ADBD /* ASPINRemoteImageDownloader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ASPINRemoteImageDownloader.m; path = Details/ASPINRemoteImageDownloader.m; sourceTree = ""; }; @@ -828,7 +827,6 @@ AC6456071B0A335000CF11B8 /* ASCellNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASCellNode.mm; sourceTree = ""; }; AC7A2C161BDE11DF0093FE1A /* ASTableViewInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASTableViewInternal.h; sourceTree = ""; }; ACC945A81BA9E7A0005E1FB8 /* ASViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASViewController.h; sourceTree = ""; }; - ACC945AA1BA9E7C1005E1FB8 /* ASViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASViewController.m; sourceTree = ""; }; ACF6ED011B17843500DA7C62 /* ASBackgroundLayoutSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASBackgroundLayoutSpec.h; path = AsyncDisplayKit/Layout/ASBackgroundLayoutSpec.h; sourceTree = ""; }; ACF6ED021B17843500DA7C62 /* ASBackgroundLayoutSpec.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; name = ASBackgroundLayoutSpec.mm; path = AsyncDisplayKit/Layout/ASBackgroundLayoutSpec.mm; sourceTree = ""; }; ACF6ED031B17843500DA7C62 /* ASCenterLayoutSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASCenterLayoutSpec.h; path = AsyncDisplayKit/Layout/ASCenterLayoutSpec.h; sourceTree = ""; }; @@ -872,7 +870,6 @@ AEEC47E01C20C2DD00EC1693 /* ASVideoNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASVideoNode.mm; sourceTree = ""; }; AEEC47E31C21D3D200EC1693 /* ASVideoNodeTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASVideoNodeTests.m; sourceTree = ""; }; B0F880581BEAEC7500D17647 /* ASTableNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASTableNode.h; sourceTree = ""; }; - B0F880591BEAEC7500D17647 /* ASTableNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASTableNode.m; sourceTree = ""; }; B13CA0F61C519E9400E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASCollectionViewLayoutFacilitatorProtocol.h; sourceTree = ""; }; B13CA0FF1C52004900E031AB /* ASCollectionNode+Beta.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ASCollectionNode+Beta.h"; sourceTree = ""; }; B30BF6501C5964B0004FCD53 /* ASLayoutManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASLayoutManager.h; path = TextKit/ASLayoutManager.h; sourceTree = ""; }; @@ -1073,7 +1070,7 @@ D785F6601A74327E00291744 /* ASScrollNode.h */, D785F6611A74327E00291744 /* ASScrollNode.m */, B0F880581BEAEC7500D17647 /* ASTableNode.h */, - B0F880591BEAEC7500D17647 /* ASTableNode.m */, + 9CFFC6C11CCAC768006A6476 /* ASTableNode.mm */, 055F1A3219ABD3E3004DAFF1 /* ASTableView.h */, 055F1A3319ABD3E3004DAFF1 /* ASTableView.mm */, AC7A2C161BDE11DF0093FE1A /* ASTableViewInternal.h */, @@ -1082,7 +1079,7 @@ A373200E1C571B050011FC94 /* ASTextNode+Beta.h */, 058D09E0195D050800B7D73C /* ASTextNode.mm */, ACC945A81BA9E7A0005E1FB8 /* ASViewController.h */, - ACC945AA1BA9E7C1005E1FB8 /* ASViewController.m */, + 9CFFC6BF1CCAC73C006A6476 /* ASViewController.mm */, 6BDC61F51978FEA400E50D21 /* AsyncDisplayKit.h */, 764D83D21C8EA515009B4FB8 /* AsyncDisplayKit+Debug.h */, 764D83D31C8EA515009B4FB8 /* AsyncDisplayKit+Debug.m */, @@ -1167,6 +1164,7 @@ 058D09E1195D050800B7D73C /* Details */ = { isa = PBXGroup; children = ( + 9CFFC6BD1CCAC52B006A6476 /* ASEnvironment.mm */, 058D09E2195D050800B7D73C /* _ASDisplayLayer.h */, 058D09E3195D050800B7D73C /* _ASDisplayLayer.mm */, 058D09E4195D050800B7D73C /* _ASDisplayView.h */, @@ -1187,7 +1185,6 @@ 05A6D05819D0EB64002DD95E /* ASDealloc2MainObject.h */, 05A6D05919D0EB64002DD95E /* ASDealloc2MainObject.m */, 698548611CA9E025008A345F /* ASEnvironment.h */, - 698548621CA9E025008A345F /* ASEnvironment.m */, 4640521B1A3F83C40061C0BA /* ASFlowLayoutController.h */, 4640521C1A3F83C40061C0BA /* ASFlowLayoutController.mm */, 058D09E6195D050800B7D73C /* ASHighlightOverlayLayer.h */, @@ -1982,6 +1979,7 @@ 92DD2FE41BF4B97E0074C9DD /* ASMapNode.mm in Sources */, DBC452DC1C5BF64600B16017 /* NSArray+Diffing.m in Sources */, AC3C4A521A1139C100143C57 /* ASCollectionView.mm in Sources */, + 9CFFC6C21CCAC768006A6476 /* ASTableNode.mm in Sources */, 205F0E1E1B373A2C007741D0 /* ASCollectionViewLayoutController.mm in Sources */, 058D0A13195D050800B7D73C /* ASControlNode.mm in Sources */, 464052211A3F83C40061C0BA /* ASDataController.mm in Sources */, @@ -2007,7 +2005,6 @@ 430E7C911B4C23F100697A4C /* ASIndexPath.m in Sources */, ACF6ED231B17843500DA7C62 /* ASInsetLayoutSpec.mm in Sources */, ACF6ED4C1B17847A00DA7C62 /* ASInternalHelpers.mm in Sources */, - 698548651CA9E025008A345F /* ASEnvironment.m in Sources */, ACF6ED251B17843500DA7C62 /* ASLayout.mm in Sources */, DB55C2631C6408D6004EDCF5 /* _ASTransitionContext.m in Sources */, 92074A631CC8BA1900918F75 /* ASImageNode+tvOS.m in Sources */, @@ -2050,13 +2047,13 @@ ACF6ED321B17843500DA7C62 /* ASStaticLayoutSpec.mm in Sources */, AC026B6B1BD57D6F00BBC17E /* ASChangeSetDataController.m in Sources */, 68355B311CB5799E001D4E68 /* ASImageNode+AnimatedImage.mm in Sources */, + 9CFFC6C01CCAC73C006A6476 /* ASViewController.mm in Sources */, 055F1A3519ABD3E3004DAFF1 /* ASTableView.mm in Sources */, 058D0A17195D050800B7D73C /* ASTextNode.mm in Sources */, 257754AC1BEE44CD00737CA5 /* ASTextKitRenderer.mm in Sources */, - ACC945AB1BA9E7C1005E1FB8 /* ASViewController.m in Sources */, - B0F8805B1BEAEC7500D17647 /* ASTableNode.m in Sources */, 205F0E221B376416007741D0 /* CGRect+ASConvenience.m in Sources */, 257754B21BEE44CD00737CA5 /* ASTextKitShadower.mm in Sources */, + 9CFFC6BE1CCAC52B006A6476 /* ASEnvironment.mm in Sources */, 058D0A21195D050800B7D73C /* NSMutableAttributedString+TextKitAdditions.m in Sources */, 205F0E101B371875007741D0 /* UICollectionViewLayout+ASConvenience.m in Sources */, CC7FD9DF1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.m in Sources */, @@ -2121,8 +2118,6 @@ B35062421B010EFD0018CF92 /* _ASAsyncTransactionGroup.m in Sources */, B350624A1B010EFD0018CF92 /* _ASCoreAnimationExtras.mm in Sources */, 68EE0DC01C1B4ED300BA1B99 /* ASMainSerialQueue.mm in Sources */, - 698548661CA9E025008A345F /* ASEnvironment.m in Sources */, - 2767E9421BB19BD600EA9B77 /* ASViewController.m in Sources */, B35062101B010EFD0018CF92 /* _ASDisplayLayer.mm in Sources */, 9C55866B1BD54A1900B50E3A /* ASAsciiArtBoxCreator.m in Sources */, B35062121B010EFD0018CF92 /* _ASDisplayView.mm in Sources */, @@ -2207,7 +2202,6 @@ B350620B1B010EFD0018CF92 /* ASTableView.mm in Sources */, B350620E1B010EFD0018CF92 /* ASTextNode.mm in Sources */, 68355B3E1CB57A60001D4E68 /* ASPINRemoteImageDownloader.m in Sources */, - C78F7E2A1BF7808300CDEAFC /* ASTableNode.m in Sources */, 509E68661B3AEDD7009B9150 /* CGRect+ASConvenience.m in Sources */, 254C6B8D1BF94F8A003EC431 /* ASEqualityHashHelpers.mm in Sources */, 254C6B871BF94F8A003EC431 /* ASTextKitEntityAttribute.m in Sources */, diff --git a/AsyncDisplayKit/ASCollectionNode.mm b/AsyncDisplayKit/ASCollectionNode.mm index d33ef7bb0d..6a6a1ead2e 100644 --- a/AsyncDisplayKit/ASCollectionNode.mm +++ b/AsyncDisplayKit/ASCollectionNode.mm @@ -10,6 +10,7 @@ #import "ASCollectionInternal.h" #import "ASCollectionViewLayoutFacilitatorProtocol.h" #import "ASDisplayNode+Subclasses.h" +#import "ASEnvironmentInternal.h" #import "ASRangeControllerUpdateRangeProtocol+Beta.h" #include @@ -244,4 +245,6 @@ [self.view reloadDataImmediately]; } +ASDisplayTraitsCollectionTableSetEnvironmentState + @end diff --git a/AsyncDisplayKit/ASCollectionView.mm b/AsyncDisplayKit/ASCollectionView.mm index b5a246e794..c379f3cbce 100644 --- a/AsyncDisplayKit/ASCollectionView.mm +++ b/AsyncDisplayKit/ASCollectionView.mm @@ -91,7 +91,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; #pragma mark - #pragma mark ASCollectionView. -@interface ASCollectionView () { +@interface ASCollectionView () { ASCollectionViewProxy *_proxyDataSource; ASCollectionViewProxy *_proxyDelegate; @@ -225,6 +225,7 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; _dataController = [[ASCollectionDataController alloc] initWithAsyncDataFetching:NO]; _dataController.delegate = _rangeController; _dataController.dataSource = self; + _dataController.environmentDelegate = self; _batchContext = [[ASBatchContext alloc] init]; @@ -917,6 +918,14 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell"; } } +- (id)dataControllerEnvironment +{ + if (self.collectionNode) { + return self.collectionNode; + } + return self.strongCollectionNode; +} + #pragma mark - ASCollectionViewDataControllerSource Supplementary view support - (ASCellNode *)dataController:(ASCollectionDataController *)dataController supplementaryNodeOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath diff --git a/AsyncDisplayKit/ASDisplayNode.mm b/AsyncDisplayKit/ASDisplayNode.mm index 6e54a450c1..3cbb57add1 100644 --- a/AsyncDisplayKit/ASDisplayNode.mm +++ b/AsyncDisplayKit/ASDisplayNode.mm @@ -2687,11 +2687,13 @@ static const char *ASDisplayNodeDrawingPriorityKey = "ASDrawingPriority"; - (ASEnvironmentState)environmentState { + ASDN::MutexLocker l(_propertyLock); return _environmentState; } - (void)setEnvironmentState:(ASEnvironmentState)environmentState { + ASDN::MutexLocker l(_propertyLock); _environmentState = environmentState; } @@ -2707,7 +2709,12 @@ static const char *ASDisplayNodeDrawingPriorityKey = "ASDrawingPriority"; - (BOOL)supportsUpwardPropagation { - return ASEnvironmentStatePropagationEnabled(); + return ASEnvironmentStateUpwardPropagationEnabled(); +} + +- (BOOL)supportsDownwardPropagation +{ + return ASEnvironmentStateDownwardPropagationEnabled(); } ASEnvironmentLayoutOptionsForwarding diff --git a/AsyncDisplayKit/ASTableNode.m b/AsyncDisplayKit/ASTableNode.mm similarity index 97% rename from AsyncDisplayKit/ASTableNode.m rename to AsyncDisplayKit/ASTableNode.mm index 22b6c3926f..16cf1cad9e 100644 --- a/AsyncDisplayKit/ASTableNode.m +++ b/AsyncDisplayKit/ASTableNode.mm @@ -6,6 +6,7 @@ // Copyright © 2015 Facebook. All rights reserved. // +#import "ASEnvironmentInternal.h" #import "ASFlowLayoutController.h" #import "ASTableViewInternal.h" #import "ASDisplayNode+Subclasses.h" @@ -158,4 +159,6 @@ [self.view clearFetchedData]; } +ASDisplayTraitsCollectionTableSetEnvironmentState + @end diff --git a/AsyncDisplayKit/ASTableView.mm b/AsyncDisplayKit/ASTableView.mm index 59066323bd..214883b524 100644 --- a/AsyncDisplayKit/ASTableView.mm +++ b/AsyncDisplayKit/ASTableView.mm @@ -16,6 +16,7 @@ #import "ASDisplayNodeExtras.h" #import "ASDisplayNode+Beta.h" #import "ASDisplayNode+FrameworkPrivate.h" +#import "ASEnvironmentInternal.h" #import "ASInternalHelpers.h" #import "ASLayout.h" #import "ASLayoutController.h" @@ -88,7 +89,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; - (instancetype)_initWithTableView:(ASTableView *)tableView; @end -@interface ASTableView () +@interface ASTableView () { ASTableViewProxy *_proxyDataSource; ASTableViewProxy *_proxyDelegate; @@ -175,6 +176,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; _dataController = [[dataControllerClass alloc] initWithAsyncDataFetching:NO]; _dataController.dataSource = self; _dataController.delegate = _rangeController; + _dataController.environmentDelegate = self; _layoutController.dataSource = _dataController; @@ -1078,6 +1080,16 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; } } +#pragma mark - ASDataControllerEnvironmentDelegate + +- (id)dataControllerEnvironment +{ + if (self.tableNode) { + return self.tableNode; + } + return self.strongTableNode; +} + #pragma mark - _ASTableViewCellDelegate - (void)didLayoutSubviewsOfTableViewCell:(_ASTableViewCell *)tableViewCell diff --git a/AsyncDisplayKit/ASViewController.h b/AsyncDisplayKit/ASViewController.h index d7286272b8..036cea4236 100644 --- a/AsyncDisplayKit/ASViewController.h +++ b/AsyncDisplayKit/ASViewController.h @@ -11,12 +11,27 @@ NS_ASSUME_NONNULL_BEGIN +typedef ASDisplayTraits (^ASDisplayTraitsForTraitCollectionBlock)(UITraitCollection *traitCollection); +typedef ASDisplayTraits (^ASDisplayTraitsForTraitWindowSizeBlock)(CGSize windowSize); + @interface ASViewController<__covariant DisplayNodeType : ASDisplayNode *> : UIViewController - (instancetype)initWithNode:(DisplayNodeType)node NS_DESIGNATED_INITIALIZER; @property (nonatomic, strong, readonly) DisplayNodeType node; +@property (nonatomic, strong) id displayTraitsContext; + +/** + * Set this block to customize the ASDisplayTraits returned when the VC transitions to the given traitCollection. + */ +@property (nonatomic, copy) ASDisplayTraitsForTraitCollectionBlock overrideDisplayTraitsWithTraitCollection; + +/** + * Set this block to customize the ASDisplayTraits returned when the VC transitions to the given window size. + */ +@property (nonatomic, copy) ASDisplayTraitsForTraitWindowSizeBlock overrideDisplayTraitsWithWindowSize; + /** * @abstract Passthrough property to the the .interfaceState of the node. * @return The current ASInterfaceState of the node, indicating whether it is visible and other situational properties. diff --git a/AsyncDisplayKit/ASViewController.m b/AsyncDisplayKit/ASViewController.mm similarity index 59% rename from AsyncDisplayKit/ASViewController.m rename to AsyncDisplayKit/ASViewController.mm index db5b1e5b4d..bf48a39862 100644 --- a/AsyncDisplayKit/ASViewController.m +++ b/AsyncDisplayKit/ASViewController.mm @@ -11,6 +11,7 @@ #import "ASDimension.h" #import "ASDisplayNode+FrameworkPrivate.h" #import "ASDisplayNode+Beta.h" +#import "ASEnvironmentInternal.h" #import "ASRangeControllerUpdateRangeProtocol+Beta.h" @implementation ASViewController @@ -42,10 +43,18 @@ _node = node; _automaticallyAdjustRangeModeBasedOnViewEvents = NO; - + return self; } +- (void)dealloc +{ + if (_displayTraitsContext != nil) { + ASDisplayTraitsClearDisplayContext(self.node); + _displayTraitsContext = nil; + } +} + - (void)loadView { ASDisplayNodeAssertTrue(!_node.layerBacked); @@ -132,4 +141,66 @@ return _node.interfaceState; } +#pragma mark - ASDisplayTraits + +- (ASDisplayTraits)displayTraitsForTraitCollection:(UITraitCollection *)traitCollection +{ + if (self.overrideDisplayTraitsWithTraitCollection) { + return self.overrideDisplayTraitsWithTraitCollection(traitCollection); + } + + ASDisplayTraits displayTraits = ASDisplayTraitsFromUITraitCollection(traitCollection); + displayTraits.displayContext = _displayTraitsContext; + return displayTraits; +} + +- (ASDisplayTraits)displayTraitsForWindowSize:(CGSize)windowSize +{ + if (self.overrideDisplayTraitsWithWindowSize) { + return self.overrideDisplayTraitsWithWindowSize(windowSize); + } + return self.node.environmentState.displayTraits; +} + +- (void)progagateNewDisplayTraits:(ASDisplayTraits)displayTraits +{ + ASEnvironmentState environmentState = self.node.environmentState; + ASDisplayTraits oldDisplayTraits = environmentState.displayTraits; + + if (ASDisplayTraitsIsEqualToASDisplayTraits(displayTraits, oldDisplayTraits) == NO) { + environmentState.displayTraits = displayTraits; + [self.node setEnvironmentState:environmentState]; + [self.node setNeedsLayout]; + + NSArray> *children = [self.node children]; + for (id child in children) { + ASEnvironmentStatePropagateDown(child, environmentState.displayTraits); + } + } +} + +- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection +{ + [super traitCollectionDidChange:previousTraitCollection]; + + ASDisplayTraits displayTraits = [self displayTraitsForTraitCollection:self.traitCollection]; + [self progagateNewDisplayTraits:displayTraits]; +} + +- (void)willTransitionToTraitCollection:(UITraitCollection *)newCollection withTransitionCoordinator:(id)coordinator +{ + [super willTransitionToTraitCollection:newCollection withTransitionCoordinator:coordinator]; + + ASDisplayTraits displayTraits = [self displayTraitsForTraitCollection:self.traitCollection]; + [self progagateNewDisplayTraits:displayTraits]; +} + +- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator +{ + [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; + + ASDisplayTraits displayTraits = [self displayTraitsForWindowSize:size]; + [self progagateNewDisplayTraits:displayTraits]; +} + @end diff --git a/AsyncDisplayKit/Details/ASDataController.h b/AsyncDisplayKit/Details/ASDataController.h index 190119ed62..7ca8caf323 100644 --- a/AsyncDisplayKit/Details/ASDataController.h +++ b/AsyncDisplayKit/Details/ASDataController.h @@ -17,6 +17,7 @@ NS_ASSUME_NONNULL_BEGIN @class ASCellNode; @class ASDataController; +@protocol ASEnvironment; typedef NSUInteger ASDataControllerAnimationOptions; @@ -64,6 +65,11 @@ FOUNDATION_EXPORT NSString * const ASDataControllerRowNodeKind; */ - (void)dataControllerUnlockDataSource; + +@end + +@protocol ASDataControllerEnvironmentDelegate +- (id)dataControllerEnvironment; @end /** @@ -122,6 +128,11 @@ FOUNDATION_EXPORT NSString * const ASDataControllerRowNodeKind; */ @property (nonatomic, weak) id delegate; +/** + * + */ +@property (nonatomic, weak) id environmentDelegate; + /** * Designated initializer. * diff --git a/AsyncDisplayKit/Details/ASDataController.mm b/AsyncDisplayKit/Details/ASDataController.mm index b84adeda48..55b43a4d71 100644 --- a/AsyncDisplayKit/Details/ASDataController.mm +++ b/AsyncDisplayKit/Details/ASDataController.mm @@ -13,6 +13,7 @@ #import "ASAssert.h" #import "ASCellNode.h" #import "ASDisplayNode.h" +#import "ASEnvironmentInternal.h" #import "ASFlowLayoutController.h" #import "ASInternalHelpers.h" #import "ASLayout.h" @@ -519,8 +520,17 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; for (NSUInteger i = 0; i < rowNum; i++) { NSIndexPath *indexPath = [sectionIndex indexPathByAddingIndex:i]; ASCellNodeBlock nodeBlock = [_dataSource dataController:self nodeBlockAtIndexPath:indexPath]; + + // When creating a node, make sure to pass along the current display traits so it will be laid out properly + ASCellNodeBlock nodeBlockPropagatingDisplayTraits = ^{ + ASCellNode *cellNode = nodeBlock(); + id environment = [self.environmentDelegate dataControllerEnvironment]; + ASEnvironmentStatePropagateDown(cellNode, [environment environmentState].displayTraits); + return cellNode; + }; + ASSizeRange constrainedSize = [self constrainedSizeForNodeOfKind:ASDataControllerRowNodeKind atIndexPath:indexPath]; - [contexts addObject:[[ASIndexedNodeContext alloc] initWithNodeBlock:nodeBlock + [contexts addObject:[[ASIndexedNodeContext alloc] initWithNodeBlock:nodeBlockPropagatingDisplayTraits indexPath:indexPath constrainedSize:constrainedSize]]; } diff --git a/AsyncDisplayKit/Details/ASEnvironment.h b/AsyncDisplayKit/Details/ASEnvironment.h index 8c473cc08c..c918d18f51 100644 --- a/AsyncDisplayKit/Details/ASEnvironment.h +++ b/AsyncDisplayKit/Details/ASEnvironment.h @@ -14,6 +14,8 @@ #import "ASStackLayoutDefines.h" #import "ASRelativeSize.h" +@protocol ASEnvironment; +@class UITraitCollection; ASDISPLAYNODE_EXTERN_C_BEGIN NS_ASSUME_NONNULL_BEGIN @@ -59,17 +61,50 @@ typedef struct ASEnvironmentHierarchyState { unsigned layoutPending:1; // = NO } ASEnvironmentHierarchyState; +#pragma mark - ASDisplayTraits + +typedef struct ASDisplayTraits { + CGFloat displayScale; + UIUserInterfaceSizeClass horizontalSizeClass; + 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 + // trait collcetion 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. + // + // An added precaution is to call ASDisplayTraitsClearDisplayContext from your ASVC's desctructor + // which will propagate a nil displayContext to its subnodes. + //__unsafe_unretained id displayContext; + id __unsafe_unretained displayContext; +} ASDisplayTraits; + +extern void ASDisplayTraitsClearDisplayContext(id rootEnvironment); + +extern ASDisplayTraits ASDisplayTraitsFromUITraitCollection(UITraitCollection *traitCollection); +extern BOOL ASDisplayTraitsIsEqualToASDisplayTraits(ASDisplayTraits displayTraits0, ASDisplayTraits displayTraits1); #pragma mark - ASEnvironmentState typedef struct ASEnvironmentState { struct ASEnvironmentHierarchyState hierarchyState; struct ASEnvironmentLayoutOptionsState layoutOptionsState; + struct ASDisplayTraits displayTraits; } ASEnvironmentState; extern ASEnvironmentState ASEnvironmentStateMakeDefault(); ASDISPLAYNODE_EXTERN_C_END +@class ASTraitCollection; #pragma mark - ASEnvironment @@ -93,6 +128,33 @@ ASDISPLAYNODE_EXTERN_C_END /// Classes should implement this method and return YES / NO dependent if upward propagation is enabled or not - (BOOL)supportsUpwardPropagation; +/// Classes should implement this method and return YES / NO dependent if downware propagation is enabled or not +- (BOOL)supportsDownwardPropagation; + @end -NS_ASSUME_NONNULL_END \ No newline at end of file +// ASCollection/TableNodes don't actually have ASCellNodes as subnodes. Because of this we can't rely on display trait +// downward propagation via ASEnvironment. Instead if the new environmentState has displayTraits that are different from +// the cells', then we propagate downward explicitly and request a relayout. +// +// If there is any new downward propagating state, it should be added to this define. +// +// This logic is used in both ASCollectionNode and ASTableNode +#define ASDisplayTraitsCollectionTableSetEnvironmentState \ +- (void)setEnvironmentState:(ASEnvironmentState)environmentState\ +{\ + ASDisplayTraits oldDisplayTraits = self.environmentState.displayTraits;\ + [super setEnvironmentState:environmentState];\ + ASDisplayTraits currentDisplayTraits = environmentState.displayTraits;\ + if (ASDisplayTraitsIsEqualToASDisplayTraits(currentDisplayTraits, oldDisplayTraits) == NO) {\ + NSArray *> *completedNodes = [self.view.dataController completedNodes];\ + for (NSArray *sectionArray in completedNodes) {\ + for (ASCellNode *cellNode in sectionArray) {\ + ASEnvironmentStatePropagateDown(cellNode, currentDisplayTraits);\ + [cellNode setNeedsLayout];\ + }\ + }\ + }\ +}\ + +NS_ASSUME_NONNULL_END diff --git a/AsyncDisplayKit/Details/ASEnvironment.m b/AsyncDisplayKit/Details/ASEnvironment.m deleted file mode 100644 index f3b2039f8f..0000000000 --- a/AsyncDisplayKit/Details/ASEnvironment.m +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2014-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - */ - -#import "ASEnvironment.h" - -ASEnvironmentLayoutOptionsState _ASEnvironmentLayoutOptionsStateMakeDefault() -{ - return (ASEnvironmentLayoutOptionsState) { - // Default values can be defined in here - }; -} - -ASEnvironmentHierarchyState _ASEnvironmentHierarchyStateMakeDefault() -{ - return (ASEnvironmentHierarchyState) { - // Default values can be defined in here - }; -} - -ASEnvironmentState ASEnvironmentStateMakeDefault() -{ - return (ASEnvironmentState) { - .layoutOptionsState = _ASEnvironmentLayoutOptionsStateMakeDefault(), - .hierarchyState = _ASEnvironmentHierarchyStateMakeDefault() - }; -} \ No newline at end of file diff --git a/AsyncDisplayKit/Details/ASEnvironment.mm b/AsyncDisplayKit/Details/ASEnvironment.mm new file mode 100644 index 0000000000..1439c8200f --- /dev/null +++ b/AsyncDisplayKit/Details/ASEnvironment.mm @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import "ASEnvironment.h" +#import "ASEnvironmentInternal.h" + +ASEnvironmentLayoutOptionsState _ASEnvironmentLayoutOptionsStateMakeDefault() +{ + return (ASEnvironmentLayoutOptionsState) { + // Default values can be defined in here + }; +} + +ASEnvironmentHierarchyState _ASEnvironmentHierarchyStateMakeDefault() +{ + return (ASEnvironmentHierarchyState) { + // Default values can be defined in here + }; +} + +extern void ASDisplayTraitsClearDisplayContext(id rootEnvironment) +{ + ASEnvironmentState envState = [rootEnvironment environmentState]; + ASDisplayTraits displayTraits = envState.displayTraits; + displayTraits.displayContext = nil; + envState.displayTraits = displayTraits; + [rootEnvironment setEnvironmentState:envState]; + + for (id child in [rootEnvironment children]) { + ASEnvironmentStatePropagateDown(child, displayTraits); + } +} + +ASDisplayTraits _ASDisplayTraitsMakeDefault() +{ + return (ASDisplayTraits) { + // Default values can be defined in here + }; +} + +ASDisplayTraits ASDisplayTraitsFromUITraitCollection(UITraitCollection *traitCollection) +{ + return (ASDisplayTraits) { + .displayScale = traitCollection.displayScale, + .horizontalSizeClass = traitCollection.horizontalSizeClass, + .userInterfaceIdiom = traitCollection.userInterfaceIdiom, + .verticalSizeClass = traitCollection.verticalSizeClass, + .forceTouchCapability = traitCollection.forceTouchCapability, + }; +} + +BOOL ASDisplayTraitsIsEqualToASDisplayTraits(ASDisplayTraits displayTraits0, ASDisplayTraits displayTraits1) +{ + return + displayTraits0.verticalSizeClass == displayTraits1.verticalSizeClass && + displayTraits0.horizontalSizeClass == displayTraits1.horizontalSizeClass && + displayTraits0.displayScale == displayTraits1.displayScale && + displayTraits0.userInterfaceIdiom == displayTraits1.userInterfaceIdiom && + displayTraits0.forceTouchCapability == displayTraits1.forceTouchCapability; +} + +ASEnvironmentState ASEnvironmentStateMakeDefault() +{ + return (ASEnvironmentState) { + .layoutOptionsState = _ASEnvironmentLayoutOptionsStateMakeDefault(), + .hierarchyState = _ASEnvironmentHierarchyStateMakeDefault(), + .displayTraits = _ASDisplayTraitsMakeDefault() + }; +} + diff --git a/AsyncDisplayKit/Layout/ASLayoutSpec.mm b/AsyncDisplayKit/Layout/ASLayoutSpec.mm index d5830d0c79..48f15bfc17 100644 --- a/AsyncDisplayKit/Layout/ASLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASLayoutSpec.mm @@ -80,7 +80,7 @@ id finalLayoutable = [child finalLayoutable]; if (finalLayoutable != child) { - if (ASEnvironmentStatePropagationEnabled()) { + if (ASEnvironmentStateUpwardPropagationEnabled()) { ASEnvironmentStatePropagateUp(finalLayoutable, child.environmentState.layoutOptionsState); } else { // If state propagation is not enabled the layout options state needs to be copied manually @@ -168,11 +168,13 @@ - (ASEnvironmentState)environmentState { + ASDN::MutexLocker l(_propertyLock); return _environmentState; } - (void)setEnvironmentState:(ASEnvironmentState)environmentState { + ASDN::MutexLocker l(_propertyLock); _environmentState = environmentState; } @@ -181,7 +183,12 @@ // the specifications that are known to have more than one. - (BOOL)supportsUpwardPropagation { - return ASEnvironmentStatePropagationEnabled(); + return ASEnvironmentStateUpwardPropagationEnabled(); +} + +- (BOOL)supportsDownwardPropagation +{ + return ASEnvironmentStateDownwardPropagationEnabled(); } - (void)propagateUpLayoutable:(id)layoutable diff --git a/AsyncDisplayKit/Layout/ASLayoutablePrivate.h b/AsyncDisplayKit/Layout/ASLayoutablePrivate.h index f218e41725..1ca166c7f0 100644 --- a/AsyncDisplayKit/Layout/ASLayoutablePrivate.h +++ b/AsyncDisplayKit/Layout/ASLayoutablePrivate.h @@ -79,7 +79,7 @@ extern void ASLayoutableClearCurrentContext(); #define ASEnvironmentLayoutOptionsForwarding \ - (void)propagateUpLayoutOptionsState\ {\ - if (!ASEnvironmentStatePropagationEnabled()) {\ + if (!ASEnvironmentStateUpwardPropagationEnabled()) {\ return;\ }\ id parent = [self parent];\ diff --git a/AsyncDisplayKit/Private/ASEnvironmentInternal.h b/AsyncDisplayKit/Private/ASEnvironmentInternal.h index 9bd2c305d4..adfefcc70d 100644 --- a/AsyncDisplayKit/Private/ASEnvironmentInternal.h +++ b/AsyncDisplayKit/Private/ASEnvironmentInternal.h @@ -12,7 +12,8 @@ #pragma once -BOOL ASEnvironmentStatePropagationEnabled(); +BOOL ASEnvironmentStateUpwardPropagationEnabled(); +BOOL ASEnvironmentStateDownwardPropagationEnabled(); #pragma mark - Set and get extensible values for layout options @@ -45,10 +46,12 @@ static const struct ASEnvironmentStateExtensions ASEnvironmentDefaultStateExtens static const struct ASEnvironmentLayoutOptionsState ASEnvironmentDefaultLayoutOptionsState = {}; ASEnvironmentState ASEnvironmentMergeObjectAndState(ASEnvironmentState environmentState, ASEnvironmentLayoutOptionsState state, ASEnvironmentStatePropagation propagation); - static const struct ASEnvironmentHierarchyState ASEnvironmentDefaultHierarchyState = {}; ASEnvironmentState ASEnvironmentMergeObjectAndState(ASEnvironmentState environmentState, ASEnvironmentHierarchyState state, ASEnvironmentStatePropagation propagation); +static const struct ASDisplayTraits ASEnvironmentDefaultDisplayTraits = {}; +ASEnvironmentState ASEnvironmentMergeObjectAndState(ASEnvironmentState environmentState, ASDisplayTraits state, ASEnvironmentStatePropagation propagation); + #pragma mark - Propagation diff --git a/AsyncDisplayKit/Private/ASEnvironmentInternal.mm b/AsyncDisplayKit/Private/ASEnvironmentInternal.mm index 83ea991b85..b22ab3ee97 100644 --- a/AsyncDisplayKit/Private/ASEnvironmentInternal.mm +++ b/AsyncDisplayKit/Private/ASEnvironmentInternal.mm @@ -15,11 +15,17 @@ //#define LOG(...) NSLog(__VA_ARGS__) #define LOG(...) -#define AS_SUPPORT_PROPAGATION NO +#define AS_SUPPORT_UPWARD_PROPAGATION NO +#define AS_SUPPORT_DOWNWARD_PROPAGATION YES -BOOL ASEnvironmentStatePropagationEnabled() +BOOL ASEnvironmentStateUpwardPropagationEnabled() { - return AS_SUPPORT_PROPAGATION; + return AS_SUPPORT_UPWARD_PROPAGATION; +} + +BOOL ASEnvironmentStateDownwardPropagationEnabled() +{ + return AS_SUPPORT_DOWNWARD_PROPAGATION; } @@ -106,15 +112,15 @@ UIEdgeInsets _ASEnvironmentLayoutOptionsExtensionGetEdgeInsetsAtIndex(id '../..' diff --git a/examples/DisplayTraits/Sample.xcodeproj/project.pbxproj b/examples/DisplayTraits/Sample.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..b46865ed75 --- /dev/null +++ b/examples/DisplayTraits/Sample.xcodeproj/project.pbxproj @@ -0,0 +1,379 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 05E2128719D4DB510098F589 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 05E2128619D4DB510098F589 /* main.m */; }; + 05E2128A19D4DB510098F589 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 05E2128919D4DB510098F589 /* AppDelegate.m */; }; + 05E2128D19D4DB510098F589 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 05E2128C19D4DB510098F589 /* ViewController.m */; }; + 3EC0CDCBA10D483D9F386E5E /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3D24B17D1E4A4E7A9566C5E9 /* libPods.a */; }; + 9C37D01E1CC94BC9004C8BC1 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9C37D01D1CC94BC9004C8BC1 /* Launch Screen.storyboard */; }; + 9CACC7811CCEAF9E009A1613 /* TableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9CACC7801CCEAF9E009A1613 /* TableViewController.m */; }; + 9CACC7841CCEAFAE009A1613 /* CollectionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9CACC7831CCEAFAE009A1613 /* CollectionViewController.m */; }; + 9CACC7871CCEBD3B009A1613 /* KittenNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 9CACC7861CCEBD3B009A1613 /* KittenNode.m */; }; + 9CACC78A1CCEC82C009A1613 /* OverrideViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9CACC7891CCEC82C009A1613 /* OverrideViewController.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 05E2128119D4DB510098F589 /* Sample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Sample.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 05E2128519D4DB510098F589 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 05E2128619D4DB510098F589 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 05E2128819D4DB510098F589 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 05E2128919D4DB510098F589 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 05E2128B19D4DB510098F589 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; + 05E2128C19D4DB510098F589 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; + 088AA6578212BE9BFBB07B70 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; }; + 3D24B17D1E4A4E7A9566C5E9 /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 9C37D01D1CC94BC9004C8BC1 /* Launch Screen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = "Launch Screen.storyboard"; sourceTree = ""; }; + 9CACC77F1CCEAF9E009A1613 /* TableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TableViewController.h; sourceTree = ""; }; + 9CACC7801CCEAF9E009A1613 /* TableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TableViewController.m; sourceTree = ""; }; + 9CACC7821CCEAFAE009A1613 /* CollectionViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CollectionViewController.h; sourceTree = ""; }; + 9CACC7831CCEAFAE009A1613 /* CollectionViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CollectionViewController.m; sourceTree = ""; }; + 9CACC7851CCEBD3B009A1613 /* KittenNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KittenNode.h; sourceTree = ""; }; + 9CACC7861CCEBD3B009A1613 /* KittenNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KittenNode.m; sourceTree = ""; }; + 9CACC7881CCEC82C009A1613 /* OverrideViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OverrideViewController.h; sourceTree = ""; }; + 9CACC7891CCEC82C009A1613 /* OverrideViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OverrideViewController.m; sourceTree = ""; }; + C068F1D3F0CC317E895FCDAB /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 05E2127E19D4DB510098F589 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 3EC0CDCBA10D483D9F386E5E /* libPods.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 05E2127819D4DB510098F589 = { + isa = PBXGroup; + children = ( + 05E2128319D4DB510098F589 /* Sample */, + 05E2128219D4DB510098F589 /* Products */, + 1A943BF0259746F18D6E423F /* Frameworks */, + 1AE410B73DA5C3BD087ACDD7 /* Pods */, + ); + indentWidth = 2; + sourceTree = ""; + tabWidth = 2; + usesTabs = 0; + }; + 05E2128219D4DB510098F589 /* Products */ = { + isa = PBXGroup; + children = ( + 05E2128119D4DB510098F589 /* Sample.app */, + ); + name = Products; + sourceTree = ""; + }; + 05E2128319D4DB510098F589 /* Sample */ = { + isa = PBXGroup; + children = ( + 05E2128819D4DB510098F589 /* AppDelegate.h */, + 05E2128919D4DB510098F589 /* AppDelegate.m */, + 05E2128B19D4DB510098F589 /* ViewController.h */, + 05E2128C19D4DB510098F589 /* ViewController.m */, + 05E2128419D4DB510098F589 /* Supporting Files */, + 9CACC77F1CCEAF9E009A1613 /* TableViewController.h */, + 9CACC7801CCEAF9E009A1613 /* TableViewController.m */, + 9CACC7821CCEAFAE009A1613 /* CollectionViewController.h */, + 9CACC7831CCEAFAE009A1613 /* CollectionViewController.m */, + 9CACC7851CCEBD3B009A1613 /* KittenNode.h */, + 9CACC7861CCEBD3B009A1613 /* KittenNode.m */, + 9CACC7881CCEC82C009A1613 /* OverrideViewController.h */, + 9CACC7891CCEC82C009A1613 /* OverrideViewController.m */, + ); + path = Sample; + sourceTree = ""; + }; + 05E2128419D4DB510098F589 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 05E2128519D4DB510098F589 /* Info.plist */, + 05E2128619D4DB510098F589 /* main.m */, + 9C37D01D1CC94BC9004C8BC1 /* Launch Screen.storyboard */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 1A943BF0259746F18D6E423F /* Frameworks */ = { + isa = PBXGroup; + children = ( + 3D24B17D1E4A4E7A9566C5E9 /* libPods.a */, + ); + name = Frameworks; + sourceTree = ""; + }; + 1AE410B73DA5C3BD087ACDD7 /* Pods */ = { + isa = PBXGroup; + children = ( + C068F1D3F0CC317E895FCDAB /* Pods.debug.xcconfig */, + 088AA6578212BE9BFBB07B70 /* Pods.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 05E2128019D4DB510098F589 /* Sample */ = { + isa = PBXNativeTarget; + buildConfigurationList = 05E212A419D4DB510098F589 /* Build configuration list for PBXNativeTarget "Sample" */; + buildPhases = ( + E080B80F89C34A25B3488E26 /* Check Pods Manifest.lock */, + 05E2127D19D4DB510098F589 /* Sources */, + 05E2127E19D4DB510098F589 /* Frameworks */, + 05E2127F19D4DB510098F589 /* Resources */, + F012A6F39E0149F18F564F50 /* Copy Pods Resources */, + FFF65E837E66ADA71296F0FF /* Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Sample; + productName = Sample; + productReference = 05E2128119D4DB510098F589 /* Sample.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 05E2127919D4DB510098F589 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0600; + ORGANIZATIONNAME = Facebook; + TargetAttributes = { + 05E2128019D4DB510098F589 = { + CreatedOnToolsVersion = 6.0.1; + }; + }; + }; + buildConfigurationList = 05E2127C19D4DB510098F589 /* Build configuration list for PBXProject "Sample" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 05E2127819D4DB510098F589; + productRefGroup = 05E2128219D4DB510098F589 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 05E2128019D4DB510098F589 /* Sample */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 05E2127F19D4DB510098F589 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 9C37D01E1CC94BC9004C8BC1 /* Launch Screen.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + E080B80F89C34A25B3488E26 /* Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; + showEnvVarsInLog = 0; + }; + F012A6F39E0149F18F564F50 /* Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + FFF65E837E66ADA71296F0FF /* Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Embed Pods Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 05E2127D19D4DB510098F589 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 05E2128D19D4DB510098F589 /* ViewController.m in Sources */, + 9CACC78A1CCEC82C009A1613 /* OverrideViewController.m in Sources */, + 05E2128A19D4DB510098F589 /* AppDelegate.m in Sources */, + 05E2128719D4DB510098F589 /* main.m in Sources */, + 9CACC7841CCEAFAE009A1613 /* CollectionViewController.m in Sources */, + 9CACC7871CCEBD3B009A1613 /* KittenNode.m in Sources */, + 9CACC7811CCEAF9E009A1613 /* TableViewController.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 05E212A219D4DB510098F589 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 05E212A319D4DB510098F589 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 05E212A519D4DB510098F589 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = C068F1D3F0CC317E895FCDAB /* Pods.debug.xcconfig */; + buildSettings = { + INFOPLIST_FILE = Sample/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 05E212A619D4DB510098F589 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 088AA6578212BE9BFBB07B70 /* Pods.release.xcconfig */; + buildSettings = { + INFOPLIST_FILE = Sample/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 05E2127C19D4DB510098F589 /* Build configuration list for PBXProject "Sample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 05E212A219D4DB510098F589 /* Debug */, + 05E212A319D4DB510098F589 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 05E212A419D4DB510098F589 /* Build configuration list for PBXNativeTarget "Sample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 05E212A519D4DB510098F589 /* Debug */, + 05E212A619D4DB510098F589 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 05E2127919D4DB510098F589 /* Project object */; +} diff --git a/examples/DisplayTraits/Sample.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/examples/DisplayTraits/Sample.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000..a80c038249 --- /dev/null +++ b/examples/DisplayTraits/Sample.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/examples/DisplayTraits/Sample.xcodeproj/xcshareddata/xcschemes/Sample.xcscheme b/examples/DisplayTraits/Sample.xcodeproj/xcshareddata/xcschemes/Sample.xcscheme new file mode 100644 index 0000000000..1e14aa0329 --- /dev/null +++ b/examples/DisplayTraits/Sample.xcodeproj/xcshareddata/xcschemes/Sample.xcscheme @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/DisplayTraits/Sample.xcworkspace/contents.xcworkspacedata b/examples/DisplayTraits/Sample.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000..7b5a2f3050 --- /dev/null +++ b/examples/DisplayTraits/Sample.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/examples/DisplayTraits/Sample/AppDelegate.h b/examples/DisplayTraits/Sample/AppDelegate.h new file mode 100644 index 0000000000..85855277e9 --- /dev/null +++ b/examples/DisplayTraits/Sample/AppDelegate.h @@ -0,0 +1,20 @@ +/* This file provided by Facebook is for non-commercial testing and evaluation + * purposes only. Facebook reserves all rights not expressly granted. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#import + +#define UseAutomaticLayout 1 + +@interface AppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + +@end diff --git a/examples/DisplayTraits/Sample/AppDelegate.m b/examples/DisplayTraits/Sample/AppDelegate.m new file mode 100644 index 0000000000..63928f1c38 --- /dev/null +++ b/examples/DisplayTraits/Sample/AppDelegate.m @@ -0,0 +1,31 @@ +/* This file provided by Facebook is for non-commercial testing and evaluation + * purposes only. Facebook reserves all rights not expressly granted. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#import "AppDelegate.h" + +#import "ViewController.h" +#import "TableViewController.h" +#import "CollectionViewController.h" + +@implementation AppDelegate + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ + self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; + self.window.backgroundColor = [UIColor whiteColor]; + UITabBarController *tabController = [[UITabBarController alloc] init]; + [tabController setViewControllers:@[[[ViewController alloc] init], [[TableViewController alloc] init], [[CollectionViewController alloc] init]]]; + self.window.rootViewController = tabController; + [self.window makeKeyAndVisible]; + return YES; +} + +@end diff --git a/examples/DisplayTraits/Sample/CollectionViewController.h b/examples/DisplayTraits/Sample/CollectionViewController.h new file mode 100644 index 0000000000..613cf835e4 --- /dev/null +++ b/examples/DisplayTraits/Sample/CollectionViewController.h @@ -0,0 +1,15 @@ +/* This file provided by Facebook is for non-commercial testing and evaluation + * purposes only. Facebook reserves all rights not expressly granted. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#import + +@interface CollectionViewController : ASViewController +@end diff --git a/examples/DisplayTraits/Sample/CollectionViewController.m b/examples/DisplayTraits/Sample/CollectionViewController.m new file mode 100644 index 0000000000..f4cba2ae37 --- /dev/null +++ b/examples/DisplayTraits/Sample/CollectionViewController.m @@ -0,0 +1,72 @@ +/* This file provided by Facebook is for non-commercial testing and evaluation + * purposes only. Facebook reserves all rights not expressly granted. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#import "CollectionViewController.h" +#import "KittenNode.h" + +@interface CollectionViewController () +@property (nonatomic, strong) ASCollectionNode *collectionNode; +@end + +@implementation CollectionViewController + +- (instancetype)init +{ + UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; + layout.minimumLineSpacing = 10; + layout.minimumInteritemSpacing = 10; + + ASCollectionNode *collectionNode = [[ASCollectionNode alloc] initWithCollectionViewLayout:layout]; + + if (!(self = [super initWithNode:collectionNode])) + return nil; + + self.title = @"Collection Node"; + _collectionNode = collectionNode; + collectionNode.dataSource = self; + collectionNode.delegate = self; + return self; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + self.collectionNode.view.contentInset = UIEdgeInsetsMake(20, 10, CGRectGetHeight(self.tabBarController.tabBar.frame), 10); +} + +#pragma mark - ASCollectionDataSource + +- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section +{ + return 50; +} + +- (ASCellNode *)collectionView:(ASCollectionView *)collectionView nodeForItemAtIndexPath:(NSIndexPath *)indexPath +{ + KittenNode *cell = [[KittenNode alloc] init]; + cell.textNode.maximumNumberOfLines = 3; + cell.imageTappedBlock = ^{ + [KittenNode defaultImageTappedAction:self]; + }; + return cell; +} + +- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath +{ + ASDisplayTraits displayTraits = self.collectionNode.environmentState.displayTraits; + + if (displayTraits.horizontalSizeClass == UIUserInterfaceSizeClassRegular) { + return ASSizeRangeMake(CGSizeMake(200, 120), CGSizeMake(200, 120)); + } + return ASSizeRangeMake(CGSizeMake(132, 180), CGSizeMake(132, 180)); +} + +@end diff --git a/examples/DisplayTraits/Sample/Info.plist b/examples/DisplayTraits/Sample/Info.plist new file mode 100644 index 0000000000..acc713cc71 --- /dev/null +++ b/examples/DisplayTraits/Sample/Info.plist @@ -0,0 +1,39 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + com.facebook.AsyncDisplayKit.$(PRODUCT_NAME:rfc1034identifier) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + Launch Screen + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + UIInterfaceOrientationPortraitUpsideDown + + + diff --git a/examples/DisplayTraits/Sample/KittenNode.h b/examples/DisplayTraits/Sample/KittenNode.h new file mode 100644 index 0000000000..ae73a8900b --- /dev/null +++ b/examples/DisplayTraits/Sample/KittenNode.h @@ -0,0 +1,23 @@ +/* This file provided by Facebook is for non-commercial testing and evaluation + * purposes only. Facebook reserves all rights not expressly granted. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#import + +@interface KittenNode : ASCellNode +@property (nonatomic, strong, readonly) ASNetworkImageNode *imageNode; +@property (nonatomic, strong, readonly) ASTextNode *textNode; + +@property (nonatomic, copy) dispatch_block_t imageTappedBlock; + +// The default action when an image node is tapped. This action will create an +// OverrideVC and override its display traits to always be compact. ++ (void)defaultImageTappedAction:(ASViewController *)sourceViewController; +@end diff --git a/examples/DisplayTraits/Sample/KittenNode.m b/examples/DisplayTraits/Sample/KittenNode.m new file mode 100644 index 0000000000..d7d73c728c --- /dev/null +++ b/examples/DisplayTraits/Sample/KittenNode.m @@ -0,0 +1,170 @@ +/* This file provided by Facebook is for non-commercial testing and evaluation + * purposes only. Facebook reserves all rights not expressly granted. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#import "KittenNode.h" +#import "OverrideViewController.h" + +static const CGFloat kOuterPadding = 16.0f; +static const CGFloat kInnerPadding = 10.0f; + +@interface KittenNode () +{ + CGSize _kittenSize; +} + +@end + + +@implementation KittenNode + +// lorem ipsum text courtesy https://kittyipsum.com/ <3 ++ (NSArray *)placeholders +{ + static NSArray *placeholders = nil; + + static dispatch_once_t once; + dispatch_once(&once, ^{ + placeholders = @[ + @"Kitty ipsum dolor sit amet, purr sleep on your face lay down in your way biting, sniff tincidunt a etiam fluffy fur judging you stuck in a tree kittens.", + @"Lick tincidunt a biting eat the grass, egestas enim ut lick leap puking climb the curtains lick.", + @"Lick quis nunc toss the mousie vel, tortor pellentesque sunbathe orci turpis non tail flick suscipit sleep in the sink.", + @"Orci turpis litter box et stuck in a tree, egestas ac tempus et aliquam elit.", + @"Hairball iaculis dolor dolor neque, nibh adipiscing vehicula egestas dolor aliquam.", + @"Sunbathe fluffy fur tortor faucibus pharetra jump, enim jump on the table I don't like that food catnip toss the mousie scratched.", + @"Quis nunc nam sleep in the sink quis nunc purr faucibus, chase the red dot consectetur bat sagittis.", + @"Lick tail flick jump on the table stretching purr amet, rhoncus scratched jump on the table run.", + @"Suspendisse aliquam vulputate feed me sleep on your keyboard, rip the couch faucibus sleep on your keyboard tristique give me fish dolor.", + @"Rip the couch hiss attack your ankles biting pellentesque puking, enim suspendisse enim mauris a.", + @"Sollicitudin iaculis vestibulum toss the mousie biting attack your ankles, puking nunc jump adipiscing in viverra.", + @"Nam zzz amet neque, bat tincidunt a iaculis sniff hiss bibendum leap nibh.", + @"Chase the red dot enim puking chuf, tristique et egestas sniff sollicitudin pharetra enim ut mauris a.", + @"Sagittis scratched et lick, hairball leap attack adipiscing catnip tail flick iaculis lick.", + @"Neque neque sleep in the sink neque sleep on your face, climb the curtains chuf tail flick sniff tortor non.", + @"Ac etiam kittens claw toss the mousie jump, pellentesque rhoncus litter box give me fish adipiscing mauris a.", + @"Pharetra egestas sunbathe faucibus ac fluffy fur, hiss feed me give me fish accumsan.", + @"Tortor leap tristique accumsan rutrum sleep in the sink, amet sollicitudin adipiscing dolor chase the red dot.", + @"Knock over the lamp pharetra vehicula sleep on your face rhoncus, jump elit cras nec quis quis nunc nam.", + @"Sollicitudin feed me et ac in viverra catnip, nunc eat I don't like that food iaculis give me fish.", + ]; + }); + + return placeholders; +} + +- (instancetype)init +{ + if (!(self = [super init])) + return nil; + + _kittenSize = CGSizeMake(100,100); + + // kitten image, with a solid background colour serving as placeholder + _imageNode = [[ASNetworkImageNode alloc] init]; + _imageNode.backgroundColor = ASDisplayNodeDefaultPlaceholderColor(); + _imageNode.preferredFrameSize = _kittenSize; + [_imageNode addTarget:self action:@selector(imageTapped:) forControlEvents:ASControlNodeEventTouchUpInside]; + + CGFloat scale = [UIScreen mainScreen].scale; + _imageNode.URL = [NSURL URLWithString:[NSString stringWithFormat:@"https://placekitten.com/%zd/%zd?image=%zd", + (NSInteger)roundl(_kittenSize.width * scale), + (NSInteger)roundl(_kittenSize.height * scale), + (NSInteger)arc4random_uniform(20)]]; + [self addSubnode:_imageNode]; + + // lorem ipsum text, plus some nice styling + _textNode = [[ASTextNode alloc] init]; + _textNode.attributedString = [[NSAttributedString alloc] initWithString:[self kittyIpsum] + attributes:[self textStyle]]; + _textNode.flexShrink = YES; + _textNode.flexGrow = YES; + [self addSubnode:_textNode]; + + return self; +} + +- (void)imageTapped:(id)sender +{ + if (self.imageTappedBlock) { + self.imageTappedBlock(); + } +} + +- (NSString *)kittyIpsum +{ + NSArray *placeholders = [KittenNode placeholders]; + u_int32_t ipsumCount = (u_int32_t)[placeholders count]; + u_int32_t location = arc4random_uniform(ipsumCount); + u_int32_t length = arc4random_uniform(ipsumCount - location); + + NSMutableString *string = [placeholders[location] mutableCopy]; + for (u_int32_t i = location + 1; i < location + length; i++) { + [string appendString:(i % 2 == 0) ? @"\n" : @" "]; + [string appendString:placeholders[i]]; + } + + return string; +} + +- (NSDictionary *)textStyle +{ + UIFont *font = [UIFont fontWithName:@"HelveticaNeue" size:12.0f]; + + NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; + style.paragraphSpacing = 0.5 * font.lineHeight; + style.hyphenationFactor = 1.0; + + return @{ NSFontAttributeName: font, + NSParagraphStyleAttributeName: style, + ASTextNodeWordKerningAttributeName : @.5}; +} + +- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize +{ + + ASDisplayTraits displayTraits = self.environmentState.displayTraits; + + ASStackLayoutSpec *stackSpec = [[ASStackLayoutSpec alloc] init]; + stackSpec.spacing = kInnerPadding; + stackSpec.children = @[_imageNode, _textNode]; + + if (displayTraits.horizontalSizeClass == UIUserInterfaceSizeClassRegular) { + _imageNode.alignSelf = ASStackLayoutAlignSelfStart; + stackSpec.direction = ASStackLayoutDirectionHorizontal; + } else { + _imageNode.alignSelf = ASStackLayoutAlignSelfCenter; + stackSpec.direction = ASStackLayoutDirectionVertical; + } + + return [ASInsetLayoutSpec insetLayoutSpecWithInsets:UIEdgeInsetsMake(kOuterPadding, kOuterPadding, kOuterPadding, kOuterPadding) child:stackSpec]; +} + + ++ (void)defaultImageTappedAction:(ASViewController *)sourceViewController +{ + OverrideViewController *overrideVC = [[OverrideViewController alloc] init]; + + overrideVC.overrideDisplayTraitsWithTraitCollection = ^(UITraitCollection *traitCollection) { + return (ASDisplayTraits) { + .displayScale = traitCollection.displayScale, + .horizontalSizeClass = UIUserInterfaceSizeClassCompact, + .userInterfaceIdiom = traitCollection.userInterfaceIdiom, + .verticalSizeClass = UIUserInterfaceSizeClassCompact, + .forceTouchCapability = traitCollection.forceTouchCapability, + }; + }; + + [sourceViewController presentViewController:overrideVC animated:YES completion:nil]; + overrideVC.closeBlock = ^{ + [sourceViewController dismissViewControllerAnimated:YES completion:nil]; + }; +} + +@end diff --git a/examples/DisplayTraits/Sample/Launch Screen.storyboard b/examples/DisplayTraits/Sample/Launch Screen.storyboard new file mode 100644 index 0000000000..95c8ef474d --- /dev/null +++ b/examples/DisplayTraits/Sample/Launch Screen.storyboard @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/DisplayTraits/Sample/OverrideViewController.h b/examples/DisplayTraits/Sample/OverrideViewController.h new file mode 100644 index 0000000000..9d9e69d839 --- /dev/null +++ b/examples/DisplayTraits/Sample/OverrideViewController.h @@ -0,0 +1,29 @@ +/* This file provided by Facebook is for non-commercial testing and evaluation + * purposes only. Facebook reserves all rights not expressly granted. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#import + +/* + * A simple node that displays the attribution for the kitties in the app. Note that + * for a regular horizontal size class it does something stupid and sets the font size to 100. + * It's VC, OverrideViewController, will have its display traits overridden such that + * it will always have a compact horizontal size class. + */ +@interface OverrideNode : ASDisplayNode +@end + +/* + * This is a fairly stupid VC that's main purpose is to show how to override ASDisplayTraits. + * Take a look at `defaultImageTappedAction` in KittenNode to see how this is accomplished. + */ +@interface OverrideViewController : ASViewController +@property (nonatomic, copy) dispatch_block_t closeBlock; +@end diff --git a/examples/DisplayTraits/Sample/OverrideViewController.m b/examples/DisplayTraits/Sample/OverrideViewController.m new file mode 100644 index 0000000000..7bcb3b7276 --- /dev/null +++ b/examples/DisplayTraits/Sample/OverrideViewController.m @@ -0,0 +1,95 @@ +/* This file provided by Facebook is for non-commercial testing and evaluation + * purposes only. Facebook reserves all rights not expressly granted. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#import "OverrideViewController.h" +static NSString *kLinkAttributeName = @"PlaceKittenNodeLinkAttributeName"; + +@interface OverrideNode() +@property (nonatomic, strong) ASTextNode *textNode; +@property (nonatomic, strong) ASButtonNode *buttonNode; +@end + +@implementation OverrideNode + +- (instancetype)init +{ + if (!(self = [super init])) + return nil; + + _textNode = [[ASTextNode alloc] init]; + _textNode.flexGrow = YES; + _textNode.flexShrink = YES; + _textNode.maximumNumberOfLines = 3; + [self addSubnode:_textNode]; + + _buttonNode = [[ASButtonNode alloc] init]; + [_buttonNode setAttributedTitle:[[NSAttributedString alloc] initWithString:@"Close"] forState:ASControlStateNormal]; + [self addSubnode:_buttonNode]; + + self.backgroundColor = [UIColor lightGrayColor]; + + return self; +} + +- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize +{ + CGFloat pointSize = 16.f; + ASDisplayTraits displayTraits = self.environmentState.displayTraits; + if (displayTraits.horizontalSizeClass == UIUserInterfaceSizeClassRegular) { + // This should never happen because we override the VC's display traits to always be compact. + pointSize = 100; + } + + NSString *blurb = @"kittens courtesy placekitten.com"; + NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:blurb]; + [string addAttribute:NSFontAttributeName value:[UIFont fontWithName:@"HelveticaNeue" size:pointSize] range:NSMakeRange(0, blurb.length)]; + [string addAttributes:@{ + kLinkAttributeName: [NSURL URLWithString:@"http://placekitten.com/"], + NSForegroundColorAttributeName: [UIColor grayColor], + NSUnderlineStyleAttributeName: @(NSUnderlineStyleSingle | NSUnderlinePatternDot), + } + range:[blurb rangeOfString:@"placekitten.com"]]; + + _textNode.attributedString = string; + + ASStackLayoutSpec *stackSpec = [ASStackLayoutSpec verticalStackLayoutSpec]; + stackSpec.children = @[_textNode, _buttonNode]; + stackSpec.spacing = 10; + return [ASInsetLayoutSpec insetLayoutSpecWithInsets:UIEdgeInsetsMake(40, 20, 20, 20) child:stackSpec]; +} + +@end + +@interface OverrideViewController () + +@end + +@implementation OverrideViewController + +- (instancetype)init +{ + OverrideNode *overrideNode = [[OverrideNode alloc] init]; + + if (!(self = [super initWithNode:overrideNode])) + return nil; + + [overrideNode.buttonNode addTarget:self action:@selector(closeTapped:) forControlEvents:ASControlNodeEventTouchUpInside]; + return self; +} + +- (void)closeTapped:(id)sender +{ + if (self.closeBlock) { + self.closeBlock(); + } +} + +@end diff --git a/examples/DisplayTraits/Sample/TableViewController.h b/examples/DisplayTraits/Sample/TableViewController.h new file mode 100644 index 0000000000..364dde8597 --- /dev/null +++ b/examples/DisplayTraits/Sample/TableViewController.h @@ -0,0 +1,16 @@ +/* This file provided by Facebook is for non-commercial testing and evaluation + * purposes only. Facebook reserves all rights not expressly granted. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#import + +@interface TableViewController : ASViewController + +@end diff --git a/examples/DisplayTraits/Sample/TableViewController.m b/examples/DisplayTraits/Sample/TableViewController.m new file mode 100644 index 0000000000..bd897a7c75 --- /dev/null +++ b/examples/DisplayTraits/Sample/TableViewController.m @@ -0,0 +1,62 @@ +/* This file provided by Facebook is for non-commercial testing and evaluation + * purposes only. Facebook reserves all rights not expressly granted. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#import "TableViewController.h" +#import "KittenNode.h" + +@interface TableViewController () +@property (nonatomic, strong) ASTableNode *tableNode; +@end + +@implementation TableViewController + +- (instancetype)init +{ + ASTableNode *tableNode = [[ASTableNode alloc] init]; + if (!(self = [super initWithNode:tableNode])) + return nil; + + _tableNode = tableNode; + tableNode.delegate = self; + tableNode.dataSource = self; + self.title = @"Table Node"; + return self; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + self.tableNode.view.contentInset = UIEdgeInsetsMake(CGRectGetHeight([[UIApplication sharedApplication] statusBarFrame]), 0, CGRectGetHeight(self.tabBarController.tabBar.frame), 0); +} + +#pragma mark - +#pragma mark ASTableView. + +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath +{ + [tableView deselectRowAtIndexPath:indexPath animated:YES]; +} + +- (ASCellNode *)tableView:(ASTableView *)tableView nodeForRowAtIndexPath:(NSIndexPath *)indexPath +{ + KittenNode *cell = [[KittenNode alloc] init]; + cell.imageTappedBlock = ^{ + [KittenNode defaultImageTappedAction:self]; + }; + return cell; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + return 15; +} + +@end diff --git a/examples/DisplayTraits/Sample/ViewController.h b/examples/DisplayTraits/Sample/ViewController.h new file mode 100644 index 0000000000..aa1d583729 --- /dev/null +++ b/examples/DisplayTraits/Sample/ViewController.h @@ -0,0 +1,16 @@ +/* This file provided by Facebook is for non-commercial testing and evaluation + * purposes only. Facebook reserves all rights not expressly granted. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#import + +@interface ViewController : ASViewController + +@end diff --git a/examples/DisplayTraits/Sample/ViewController.m b/examples/DisplayTraits/Sample/ViewController.m new file mode 100644 index 0000000000..42e9cb9a4a --- /dev/null +++ b/examples/DisplayTraits/Sample/ViewController.m @@ -0,0 +1,45 @@ +/* This file provided by Facebook is for non-commercial testing and evaluation + * purposes only. Facebook reserves all rights not expressly granted. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#import "ViewController.h" +#import "KittenNode.h" +#import "OverrideViewController.h" + +#import +#import + +@interface ViewController () +@end + +@implementation ViewController + +#pragma mark - +#pragma mark UIViewController. + +- (instancetype)init +{ + KittenNode *displayNode = [[KittenNode alloc] init]; + if (!(self = [super initWithNode:displayNode])) + return nil; + + self.title = @"Display Node"; + displayNode.imageTappedBlock = ^{ + [KittenNode defaultImageTappedAction:self]; + }; + return self; +} + +- (void)viewWillLayoutSubviews +{ + [super viewWillLayoutSubviews]; +} + +@end diff --git a/examples/DisplayTraits/Sample/main.m b/examples/DisplayTraits/Sample/main.m new file mode 100644 index 0000000000..ae9488711c --- /dev/null +++ b/examples/DisplayTraits/Sample/main.m @@ -0,0 +1,20 @@ +/* This file provided by Facebook is for non-commercial testing and evaluation + * purposes only. Facebook reserves all rights not expressly granted. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#import + +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} From b4a6f87ca67ee906633d9db00ca5cbb9d810733f Mon Sep 17 00:00:00 2001 From: rcancro Date: Tue, 3 May 2016 21:55:04 -0700 Subject: [PATCH 20/52] addressed some comments --- AsyncDisplayKit/ASCollectionNode.mm | 2 +- AsyncDisplayKit/ASDisplayNode.mm | 6 ++--- AsyncDisplayKit/ASTableNode.mm | 2 +- AsyncDisplayKit/ASViewController.h | 8 +++---- AsyncDisplayKit/ASViewController.mm | 18 +++++++-------- AsyncDisplayKit/Details/ASEnvironment.h | 22 +++++++++---------- AsyncDisplayKit/Details/ASEnvironment.mm | 14 ++++++------ AsyncDisplayKit/Layout/ASLayoutSpec.mm | 8 +++---- AsyncDisplayKit/Layout/ASLayoutablePrivate.h | 2 +- .../Private/ASEnvironmentInternal.h | 8 +++---- .../Private/ASEnvironmentInternal.mm | 21 +++++++++--------- .../Sample/CollectionViewController.m | 2 +- examples/DisplayTraits/Sample/KittenNode.m | 4 ++-- .../Sample/OverrideViewController.m | 2 +- 14 files changed, 59 insertions(+), 60 deletions(-) diff --git a/AsyncDisplayKit/ASCollectionNode.mm b/AsyncDisplayKit/ASCollectionNode.mm index 6a6a1ead2e..52ce5312fa 100644 --- a/AsyncDisplayKit/ASCollectionNode.mm +++ b/AsyncDisplayKit/ASCollectionNode.mm @@ -245,6 +245,6 @@ [self.view reloadDataImmediately]; } -ASDisplayTraitsCollectionTableSetEnvironmentState +ASEnvironmentDisplayTraitsCollectionTableSetEnvironmentState @end diff --git a/AsyncDisplayKit/ASDisplayNode.mm b/AsyncDisplayKit/ASDisplayNode.mm index 3cbb57add1..8ee237f50b 100644 --- a/AsyncDisplayKit/ASDisplayNode.mm +++ b/AsyncDisplayKit/ASDisplayNode.mm @@ -2709,12 +2709,12 @@ static const char *ASDisplayNodeDrawingPriorityKey = "ASDrawingPriority"; - (BOOL)supportsUpwardPropagation { - return ASEnvironmentStateUpwardPropagationEnabled(); + return ASEnvironmentStatePropagationEnabled(); } -- (BOOL)supportsDownwardPropagation +- (BOOL)supportsTraitsCollectionPropagation { - return ASEnvironmentStateDownwardPropagationEnabled(); + return ASEnvironmentStateTraitCollectionPropagationEnabled(); } ASEnvironmentLayoutOptionsForwarding diff --git a/AsyncDisplayKit/ASTableNode.mm b/AsyncDisplayKit/ASTableNode.mm index 16cf1cad9e..999e95c427 100644 --- a/AsyncDisplayKit/ASTableNode.mm +++ b/AsyncDisplayKit/ASTableNode.mm @@ -159,6 +159,6 @@ [self.view clearFetchedData]; } -ASDisplayTraitsCollectionTableSetEnvironmentState +ASEnvironmentDisplayTraitsCollectionTableSetEnvironmentState @end diff --git a/AsyncDisplayKit/ASViewController.h b/AsyncDisplayKit/ASViewController.h index 036cea4236..fda6adb12d 100644 --- a/AsyncDisplayKit/ASViewController.h +++ b/AsyncDisplayKit/ASViewController.h @@ -11,8 +11,8 @@ NS_ASSUME_NONNULL_BEGIN -typedef ASDisplayTraits (^ASDisplayTraitsForTraitCollectionBlock)(UITraitCollection *traitCollection); -typedef ASDisplayTraits (^ASDisplayTraitsForTraitWindowSizeBlock)(CGSize windowSize); +typedef ASEnvironmentDisplayTraits (^ASEnvironmentDisplayTraitsForTraitCollectionBlock)(UITraitCollection *traitCollection); +typedef ASEnvironmentDisplayTraits (^ASEnvironmentDisplayTraitsForTraitWindowSizeBlock)(CGSize windowSize); @interface ASViewController<__covariant DisplayNodeType : ASDisplayNode *> : UIViewController @@ -25,12 +25,12 @@ typedef ASDisplayTraits (^ASDisplayTraitsForTraitWindowSizeBlock)(CGSize windowS /** * Set this block to customize the ASDisplayTraits returned when the VC transitions to the given traitCollection. */ -@property (nonatomic, copy) ASDisplayTraitsForTraitCollectionBlock overrideDisplayTraitsWithTraitCollection; +@property (nonatomic, copy) ASEnvironmentDisplayTraitsForTraitCollectionBlock overrideDisplayTraitsWithTraitCollection; /** * Set this block to customize the ASDisplayTraits returned when the VC transitions to the given window size. */ -@property (nonatomic, copy) ASDisplayTraitsForTraitWindowSizeBlock overrideDisplayTraitsWithWindowSize; +@property (nonatomic, copy) ASEnvironmentDisplayTraitsForTraitWindowSizeBlock overrideDisplayTraitsWithWindowSize; /** * @abstract Passthrough property to the the .interfaceState of the node. diff --git a/AsyncDisplayKit/ASViewController.mm b/AsyncDisplayKit/ASViewController.mm index bf48a39862..6643cdcb7b 100644 --- a/AsyncDisplayKit/ASViewController.mm +++ b/AsyncDisplayKit/ASViewController.mm @@ -143,18 +143,18 @@ #pragma mark - ASDisplayTraits -- (ASDisplayTraits)displayTraitsForTraitCollection:(UITraitCollection *)traitCollection +- (ASEnvironmentDisplayTraits)displayTraitsForTraitCollection:(UITraitCollection *)traitCollection { if (self.overrideDisplayTraitsWithTraitCollection) { return self.overrideDisplayTraitsWithTraitCollection(traitCollection); } - ASDisplayTraits displayTraits = ASDisplayTraitsFromUITraitCollection(traitCollection); + ASEnvironmentDisplayTraits displayTraits = ASEnvironmentDisplayTraitsFromUITraitCollection(traitCollection); displayTraits.displayContext = _displayTraitsContext; return displayTraits; } -- (ASDisplayTraits)displayTraitsForWindowSize:(CGSize)windowSize +- (ASEnvironmentDisplayTraits)displayTraitsForWindowSize:(CGSize)windowSize { if (self.overrideDisplayTraitsWithWindowSize) { return self.overrideDisplayTraitsWithWindowSize(windowSize); @@ -162,12 +162,12 @@ return self.node.environmentState.displayTraits; } -- (void)progagateNewDisplayTraits:(ASDisplayTraits)displayTraits +- (void)progagateNewDisplayTraits:(ASEnvironmentDisplayTraits)displayTraits { ASEnvironmentState environmentState = self.node.environmentState; - ASDisplayTraits oldDisplayTraits = environmentState.displayTraits; + ASEnvironmentDisplayTraits oldDisplayTraits = environmentState.displayTraits; - if (ASDisplayTraitsIsEqualToASDisplayTraits(displayTraits, oldDisplayTraits) == NO) { + if (ASEnvironmentDisplayTraitsIsEqualToASEnvironmentDisplayTraits(displayTraits, oldDisplayTraits) == NO) { environmentState.displayTraits = displayTraits; [self.node setEnvironmentState:environmentState]; [self.node setNeedsLayout]; @@ -183,7 +183,7 @@ { [super traitCollectionDidChange:previousTraitCollection]; - ASDisplayTraits displayTraits = [self displayTraitsForTraitCollection:self.traitCollection]; + ASEnvironmentDisplayTraits displayTraits = [self displayTraitsForTraitCollection:self.traitCollection]; [self progagateNewDisplayTraits:displayTraits]; } @@ -191,7 +191,7 @@ { [super willTransitionToTraitCollection:newCollection withTransitionCoordinator:coordinator]; - ASDisplayTraits displayTraits = [self displayTraitsForTraitCollection:self.traitCollection]; + ASEnvironmentDisplayTraits displayTraits = [self displayTraitsForTraitCollection:self.traitCollection]; [self progagateNewDisplayTraits:displayTraits]; } @@ -199,7 +199,7 @@ { [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; - ASDisplayTraits displayTraits = [self displayTraitsForWindowSize:size]; + ASEnvironmentDisplayTraits displayTraits = [self displayTraitsForWindowSize:size]; [self progagateNewDisplayTraits:displayTraits]; } diff --git a/AsyncDisplayKit/Details/ASEnvironment.h b/AsyncDisplayKit/Details/ASEnvironment.h index c918d18f51..a6d74d9579 100644 --- a/AsyncDisplayKit/Details/ASEnvironment.h +++ b/AsyncDisplayKit/Details/ASEnvironment.h @@ -61,9 +61,9 @@ typedef struct ASEnvironmentHierarchyState { unsigned layoutPending:1; // = NO } ASEnvironmentHierarchyState; -#pragma mark - ASDisplayTraits +#pragma mark - ASEnvironmentDisplayTraits -typedef struct ASDisplayTraits { +typedef struct ASEnvironmentDisplayTraits { CGFloat displayScale; UIUserInterfaceSizeClass horizontalSizeClass; UIUserInterfaceIdiom userInterfaceIdiom; @@ -86,19 +86,19 @@ typedef struct ASDisplayTraits { // which will propagate a nil displayContext to its subnodes. //__unsafe_unretained id displayContext; id __unsafe_unretained displayContext; -} ASDisplayTraits; +} ASEnvironmentDisplayTraits; extern void ASDisplayTraitsClearDisplayContext(id rootEnvironment); -extern ASDisplayTraits ASDisplayTraitsFromUITraitCollection(UITraitCollection *traitCollection); -extern BOOL ASDisplayTraitsIsEqualToASDisplayTraits(ASDisplayTraits displayTraits0, ASDisplayTraits displayTraits1); +extern ASEnvironmentDisplayTraits ASEnvironmentDisplayTraitsFromUITraitCollection(UITraitCollection *traitCollection); +extern BOOL ASEnvironmentDisplayTraitsIsEqualToASEnvironmentDisplayTraits(ASEnvironmentDisplayTraits displayTraits0, ASEnvironmentDisplayTraits displayTraits1); #pragma mark - ASEnvironmentState typedef struct ASEnvironmentState { struct ASEnvironmentHierarchyState hierarchyState; struct ASEnvironmentLayoutOptionsState layoutOptionsState; - struct ASDisplayTraits displayTraits; + struct ASEnvironmentDisplayTraits displayTraits; } ASEnvironmentState; extern ASEnvironmentState ASEnvironmentStateMakeDefault(); @@ -129,7 +129,7 @@ ASDISPLAYNODE_EXTERN_C_END - (BOOL)supportsUpwardPropagation; /// Classes should implement this method and return YES / NO dependent if downware propagation is enabled or not -- (BOOL)supportsDownwardPropagation; +- (BOOL)supportsTraitsCollectionPropagation; @end @@ -140,13 +140,13 @@ ASDISPLAYNODE_EXTERN_C_END // If there is any new downward propagating state, it should be added to this define. // // This logic is used in both ASCollectionNode and ASTableNode -#define ASDisplayTraitsCollectionTableSetEnvironmentState \ +#define ASEnvironmentDisplayTraitsCollectionTableSetEnvironmentState \ - (void)setEnvironmentState:(ASEnvironmentState)environmentState\ {\ - ASDisplayTraits oldDisplayTraits = self.environmentState.displayTraits;\ + ASEnvironmentDisplayTraits oldDisplayTraits = self.environmentState.displayTraits;\ [super setEnvironmentState:environmentState];\ - ASDisplayTraits currentDisplayTraits = environmentState.displayTraits;\ - if (ASDisplayTraitsIsEqualToASDisplayTraits(currentDisplayTraits, oldDisplayTraits) == NO) {\ + ASEnvironmentDisplayTraits currentDisplayTraits = environmentState.displayTraits;\ + if (ASEnvironmentDisplayTraitsIsEqualToASEnvironmentDisplayTraits(currentDisplayTraits, oldDisplayTraits) == NO) {\ NSArray *> *completedNodes = [self.view.dataController completedNodes];\ for (NSArray *sectionArray in completedNodes) {\ for (ASCellNode *cellNode in sectionArray) {\ diff --git a/AsyncDisplayKit/Details/ASEnvironment.mm b/AsyncDisplayKit/Details/ASEnvironment.mm index 1439c8200f..d57663d90e 100644 --- a/AsyncDisplayKit/Details/ASEnvironment.mm +++ b/AsyncDisplayKit/Details/ASEnvironment.mm @@ -28,7 +28,7 @@ ASEnvironmentHierarchyState _ASEnvironmentHierarchyStateMakeDefault() extern void ASDisplayTraitsClearDisplayContext(id rootEnvironment) { ASEnvironmentState envState = [rootEnvironment environmentState]; - ASDisplayTraits displayTraits = envState.displayTraits; + ASEnvironmentDisplayTraits displayTraits = envState.displayTraits; displayTraits.displayContext = nil; envState.displayTraits = displayTraits; [rootEnvironment setEnvironmentState:envState]; @@ -38,16 +38,16 @@ extern void ASDisplayTraitsClearDisplayContext(id rootEnvironment } } -ASDisplayTraits _ASDisplayTraitsMakeDefault() +ASEnvironmentDisplayTraits _ASEnvironmentDisplayTraitsMakeDefault() { - return (ASDisplayTraits) { + return (ASEnvironmentDisplayTraits) { // Default values can be defined in here }; } -ASDisplayTraits ASDisplayTraitsFromUITraitCollection(UITraitCollection *traitCollection) +ASEnvironmentDisplayTraits ASEnvironmentDisplayTraitsFromUITraitCollection(UITraitCollection *traitCollection) { - return (ASDisplayTraits) { + return (ASEnvironmentDisplayTraits) { .displayScale = traitCollection.displayScale, .horizontalSizeClass = traitCollection.horizontalSizeClass, .userInterfaceIdiom = traitCollection.userInterfaceIdiom, @@ -56,7 +56,7 @@ ASDisplayTraits ASDisplayTraitsFromUITraitCollection(UITraitCollection *traitCol }; } -BOOL ASDisplayTraitsIsEqualToASDisplayTraits(ASDisplayTraits displayTraits0, ASDisplayTraits displayTraits1) +BOOL ASEnvironmentDisplayTraitsIsEqualToASEnvironmentDisplayTraits(ASEnvironmentDisplayTraits displayTraits0, ASEnvironmentDisplayTraits displayTraits1) { return displayTraits0.verticalSizeClass == displayTraits1.verticalSizeClass && @@ -71,7 +71,7 @@ ASEnvironmentState ASEnvironmentStateMakeDefault() return (ASEnvironmentState) { .layoutOptionsState = _ASEnvironmentLayoutOptionsStateMakeDefault(), .hierarchyState = _ASEnvironmentHierarchyStateMakeDefault(), - .displayTraits = _ASDisplayTraitsMakeDefault() + .displayTraits = _ASEnvironmentDisplayTraitsMakeDefault() }; } diff --git a/AsyncDisplayKit/Layout/ASLayoutSpec.mm b/AsyncDisplayKit/Layout/ASLayoutSpec.mm index 48f15bfc17..dc15ac2916 100644 --- a/AsyncDisplayKit/Layout/ASLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASLayoutSpec.mm @@ -80,7 +80,7 @@ id finalLayoutable = [child finalLayoutable]; if (finalLayoutable != child) { - if (ASEnvironmentStateUpwardPropagationEnabled()) { + if (ASEnvironmentStatePropagationEnabled()) { ASEnvironmentStatePropagateUp(finalLayoutable, child.environmentState.layoutOptionsState); } else { // If state propagation is not enabled the layout options state needs to be copied manually @@ -183,12 +183,12 @@ // the specifications that are known to have more than one. - (BOOL)supportsUpwardPropagation { - return ASEnvironmentStateUpwardPropagationEnabled(); + return ASEnvironmentStatePropagationEnabled(); } -- (BOOL)supportsDownwardPropagation +- (BOOL)supportsTraitsCollectionPropagation { - return ASEnvironmentStateDownwardPropagationEnabled(); + return ASEnvironmentStateTraitCollectionPropagationEnabled(); } - (void)propagateUpLayoutable:(id)layoutable diff --git a/AsyncDisplayKit/Layout/ASLayoutablePrivate.h b/AsyncDisplayKit/Layout/ASLayoutablePrivate.h index 1ca166c7f0..f218e41725 100644 --- a/AsyncDisplayKit/Layout/ASLayoutablePrivate.h +++ b/AsyncDisplayKit/Layout/ASLayoutablePrivate.h @@ -79,7 +79,7 @@ extern void ASLayoutableClearCurrentContext(); #define ASEnvironmentLayoutOptionsForwarding \ - (void)propagateUpLayoutOptionsState\ {\ - if (!ASEnvironmentStateUpwardPropagationEnabled()) {\ + if (!ASEnvironmentStatePropagationEnabled()) {\ return;\ }\ id parent = [self parent];\ diff --git a/AsyncDisplayKit/Private/ASEnvironmentInternal.h b/AsyncDisplayKit/Private/ASEnvironmentInternal.h index adfefcc70d..eeac031a6e 100644 --- a/AsyncDisplayKit/Private/ASEnvironmentInternal.h +++ b/AsyncDisplayKit/Private/ASEnvironmentInternal.h @@ -12,8 +12,8 @@ #pragma once -BOOL ASEnvironmentStateUpwardPropagationEnabled(); -BOOL ASEnvironmentStateDownwardPropagationEnabled(); +BOOL ASEnvironmentStatePropagationEnabled(); +BOOL ASEnvironmentStateTraitCollectionPropagationEnabled(); #pragma mark - Set and get extensible values for layout options @@ -49,8 +49,8 @@ ASEnvironmentState ASEnvironmentMergeObjectAndState(ASEnvironmentState environme static const struct ASEnvironmentHierarchyState ASEnvironmentDefaultHierarchyState = {}; ASEnvironmentState ASEnvironmentMergeObjectAndState(ASEnvironmentState environmentState, ASEnvironmentHierarchyState state, ASEnvironmentStatePropagation propagation); -static const struct ASDisplayTraits ASEnvironmentDefaultDisplayTraits = {}; -ASEnvironmentState ASEnvironmentMergeObjectAndState(ASEnvironmentState environmentState, ASDisplayTraits state, ASEnvironmentStatePropagation propagation); +static const struct ASEnvironmentDisplayTraits ASEnvironmentDefaultDisplayTraits = {}; +ASEnvironmentState ASEnvironmentMergeObjectAndState(ASEnvironmentState environmentState, ASEnvironmentDisplayTraits state, ASEnvironmentStatePropagation propagation); #pragma mark - Propagation diff --git a/AsyncDisplayKit/Private/ASEnvironmentInternal.mm b/AsyncDisplayKit/Private/ASEnvironmentInternal.mm index b22ab3ee97..b05df767f5 100644 --- a/AsyncDisplayKit/Private/ASEnvironmentInternal.mm +++ b/AsyncDisplayKit/Private/ASEnvironmentInternal.mm @@ -15,20 +15,19 @@ //#define LOG(...) NSLog(__VA_ARGS__) #define LOG(...) -#define AS_SUPPORT_UPWARD_PROPAGATION NO -#define AS_SUPPORT_DOWNWARD_PROPAGATION YES +#define AS_SUPPORT_PROPAGATION YES +#define AS_DOES_NOT_SUPPORT_PROPAGATION NO -BOOL ASEnvironmentStateUpwardPropagationEnabled() +BOOL ASEnvironmentStatePropagationEnabled() { - return AS_SUPPORT_UPWARD_PROPAGATION; + return AS_DOES_NOT_SUPPORT_PROPAGATION; } -BOOL ASEnvironmentStateDownwardPropagationEnabled() +BOOL ASEnvironmentStateTraitCollectionPropagationEnabled() { - return AS_SUPPORT_DOWNWARD_PROPAGATION; + return AS_SUPPORT_PROPAGATION; } - #pragma mark - Traversing an ASEnvironment Tree void ASEnvironmentPerformBlockOnObjectAndChildren(id object, void(^block)(id node)) @@ -120,7 +119,7 @@ ASEnvironmentState ASEnvironmentMergeObjectAndState(ASEnvironmentState environme // Merge object and layout options state LOG(@"Merge object and state: %@ - ASEnvironmentLayoutOptionsState", layoutOptionsState); - if (!ASEnvironmentStateUpwardPropagationEnabled() && propagation == ASEnvironmentStatePropagation::UP) { + if (!ASEnvironmentStatePropagationEnabled() && propagation == ASEnvironmentStatePropagation::UP) { return environmentState; } @@ -195,14 +194,14 @@ ASEnvironmentState ASEnvironmentMergeObjectAndState(ASEnvironmentState environme return environmentState; } -ASEnvironmentState ASEnvironmentMergeObjectAndState(ASEnvironmentState childEnvironmentState, ASDisplayTraits parentDisplayTraits, ASEnvironmentStatePropagation propagation) { - if (propagation == ASEnvironmentStatePropagation::DOWN && !ASEnvironmentStateDownwardPropagationEnabled()) { +ASEnvironmentState ASEnvironmentMergeObjectAndState(ASEnvironmentState childEnvironmentState, ASEnvironmentDisplayTraits parentDisplayTraits, ASEnvironmentStatePropagation propagation) { + if (propagation == ASEnvironmentStatePropagation::DOWN && !ASEnvironmentStateTraitCollectionPropagationEnabled()) { return childEnvironmentState; } // Support propagate down if (propagation == ASEnvironmentStatePropagation::DOWN) { - ASDisplayTraits childDisplayTraits = childEnvironmentState.displayTraits; + ASEnvironmentDisplayTraits childDisplayTraits = childEnvironmentState.displayTraits; childDisplayTraits.horizontalSizeClass = parentDisplayTraits.horizontalSizeClass; childDisplayTraits.verticalSizeClass = parentDisplayTraits.verticalSizeClass; childDisplayTraits.userInterfaceIdiom = parentDisplayTraits.userInterfaceIdiom; diff --git a/examples/DisplayTraits/Sample/CollectionViewController.m b/examples/DisplayTraits/Sample/CollectionViewController.m index f4cba2ae37..66e7b92adc 100644 --- a/examples/DisplayTraits/Sample/CollectionViewController.m +++ b/examples/DisplayTraits/Sample/CollectionViewController.m @@ -61,7 +61,7 @@ - (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath { - ASDisplayTraits displayTraits = self.collectionNode.environmentState.displayTraits; + ASEnvironmentDisplayTraits displayTraits = self.collectionNode.environmentState.displayTraits; if (displayTraits.horizontalSizeClass == UIUserInterfaceSizeClassRegular) { return ASSizeRangeMake(CGSizeMake(200, 120), CGSizeMake(200, 120)); diff --git a/examples/DisplayTraits/Sample/KittenNode.m b/examples/DisplayTraits/Sample/KittenNode.m index d7d73c728c..dd8fbc4b96 100644 --- a/examples/DisplayTraits/Sample/KittenNode.m +++ b/examples/DisplayTraits/Sample/KittenNode.m @@ -129,7 +129,7 @@ static const CGFloat kInnerPadding = 10.0f; - (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize { - ASDisplayTraits displayTraits = self.environmentState.displayTraits; + ASEnvironmentDisplayTraits displayTraits = self.environmentState.displayTraits; ASStackLayoutSpec *stackSpec = [[ASStackLayoutSpec alloc] init]; stackSpec.spacing = kInnerPadding; @@ -152,7 +152,7 @@ static const CGFloat kInnerPadding = 10.0f; OverrideViewController *overrideVC = [[OverrideViewController alloc] init]; overrideVC.overrideDisplayTraitsWithTraitCollection = ^(UITraitCollection *traitCollection) { - return (ASDisplayTraits) { + return (ASEnvironmentDisplayTraits) { .displayScale = traitCollection.displayScale, .horizontalSizeClass = UIUserInterfaceSizeClassCompact, .userInterfaceIdiom = traitCollection.userInterfaceIdiom, diff --git a/examples/DisplayTraits/Sample/OverrideViewController.m b/examples/DisplayTraits/Sample/OverrideViewController.m index 7bcb3b7276..b0024b38e7 100644 --- a/examples/DisplayTraits/Sample/OverrideViewController.m +++ b/examples/DisplayTraits/Sample/OverrideViewController.m @@ -42,7 +42,7 @@ static NSString *kLinkAttributeName = @"PlaceKittenNodeLinkAttributeName"; - (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize { CGFloat pointSize = 16.f; - ASDisplayTraits displayTraits = self.environmentState.displayTraits; + ASEnvironmentDisplayTraits displayTraits = self.environmentState.displayTraits; if (displayTraits.horizontalSizeClass == UIUserInterfaceSizeClassRegular) { // This should never happen because we override the VC's display traits to always be compact. pointSize = 100; From 35820e58a0036ae0419780891b5c37e1ad82fa0f Mon Sep 17 00:00:00 2001 From: rcancro Date: Tue, 3 May 2016 22:04:47 -0700 Subject: [PATCH 21/52] add locking to collection state propagation --- AsyncDisplayKit/ASCollectionNode.mm | 5 ++++- AsyncDisplayKit/ASTableNode.mm | 6 +++++- AsyncDisplayKit/Details/ASEnvironment.h | 3 ++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/AsyncDisplayKit/ASCollectionNode.mm b/AsyncDisplayKit/ASCollectionNode.mm index 52ce5312fa..15a19658c9 100644 --- a/AsyncDisplayKit/ASCollectionNode.mm +++ b/AsyncDisplayKit/ASCollectionNode.mm @@ -54,6 +54,9 @@ #endif @interface ASCollectionNode () +{ + ASDN::RecursiveMutex _environmentStateLock; +} @property (nonatomic) _ASCollectionPendingState *pendingState; @end @@ -245,6 +248,6 @@ [self.view reloadDataImmediately]; } -ASEnvironmentDisplayTraitsCollectionTableSetEnvironmentState +ASEnvironmentDisplayTraitsCollectionTableSetEnvironmentState(_environmentStateLock) @end diff --git a/AsyncDisplayKit/ASTableNode.mm b/AsyncDisplayKit/ASTableNode.mm index 999e95c427..6c9f35f842 100644 --- a/AsyncDisplayKit/ASTableNode.mm +++ b/AsyncDisplayKit/ASTableNode.mm @@ -21,6 +21,10 @@ @end @interface ASTableNode () +{ + ASDN::RecursiveMutex _environmentStateLock; +} + @property (nonatomic, strong) _ASTablePendingState *pendingState; @end @@ -159,6 +163,6 @@ [self.view clearFetchedData]; } -ASEnvironmentDisplayTraitsCollectionTableSetEnvironmentState +ASEnvironmentDisplayTraitsCollectionTableSetEnvironmentState(_environmentStateLock) @end diff --git a/AsyncDisplayKit/Details/ASEnvironment.h b/AsyncDisplayKit/Details/ASEnvironment.h index a6d74d9579..7f11925cd5 100644 --- a/AsyncDisplayKit/Details/ASEnvironment.h +++ b/AsyncDisplayKit/Details/ASEnvironment.h @@ -140,9 +140,10 @@ ASDISPLAYNODE_EXTERN_C_END // If there is any new downward propagating state, it should be added to this define. // // This logic is used in both ASCollectionNode and ASTableNode -#define ASEnvironmentDisplayTraitsCollectionTableSetEnvironmentState \ +#define ASEnvironmentDisplayTraitsCollectionTableSetEnvironmentState(lock) \ - (void)setEnvironmentState:(ASEnvironmentState)environmentState\ {\ + ASDN::MutexLocker l(lock);\ ASEnvironmentDisplayTraits oldDisplayTraits = self.environmentState.displayTraits;\ [super setEnvironmentState:environmentState];\ ASEnvironmentDisplayTraits currentDisplayTraits = environmentState.displayTraits;\ From f828d079faa16b62e32baa289db147554c8b2e82 Mon Sep 17 00:00:00 2001 From: rcancro Date: Wed, 4 May 2016 10:37:06 -0700 Subject: [PATCH 22/52] added nsobject based ASDisplayTraits class --- AsyncDisplayKit.xcodeproj/project.pbxproj | 12 +++ AsyncDisplayKit/ASDisplayNode.mm | 6 ++ AsyncDisplayKit/ASViewController.h | 10 +- AsyncDisplayKit/ASViewController.mm | 9 +- AsyncDisplayKit/Details/ASDisplayTraits.h | 29 ++++++ AsyncDisplayKit/Details/ASDisplayTraits.m | 91 +++++++++++++++++++ AsyncDisplayKit/Details/ASEnvironment.h | 10 +- AsyncDisplayKit/Details/ASEnvironment.mm | 21 +++-- AsyncDisplayKit/Layout/ASLayoutSpec.mm | 7 ++ Base/ASAvailability.h | 9 ++ .../Sample/CollectionViewController.m | 3 +- examples/DisplayTraits/Sample/KittenNode.m | 17 ++-- .../Sample/OverrideViewController.m | 4 +- 13 files changed, 198 insertions(+), 30 deletions(-) create mode 100644 AsyncDisplayKit/Details/ASDisplayTraits.h create mode 100644 AsyncDisplayKit/Details/ASDisplayTraits.m diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index 7c880f867d..096b77cefe 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -324,6 +324,10 @@ 9C55866C1BD54A3000B50E3A /* ASAsciiArtBoxCreator.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C5586671BD549CB00B50E3A /* ASAsciiArtBoxCreator.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9C6BB3B21B8CC9C200F13F52 /* ASStaticLayoutable.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C6BB3B01B8CC9C200F13F52 /* ASStaticLayoutable.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9C6BB3B31B8CC9C200F13F52 /* ASStaticLayoutable.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C6BB3B01B8CC9C200F13F52 /* ASStaticLayoutable.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9C70F2031CDA4EFA007D6C76 /* ASDisplayTraits.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C70F2011CDA4EFA007D6C76 /* ASDisplayTraits.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9C70F2041CDA4EFA007D6C76 /* ASDisplayTraits.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C70F2021CDA4EFA007D6C76 /* ASDisplayTraits.m */; }; + 9C70F2051CDA4F06007D6C76 /* ASDisplayTraits.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C70F2021CDA4EFA007D6C76 /* ASDisplayTraits.m */; }; + 9C70F2061CDA4F0C007D6C76 /* ASDisplayTraits.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C70F2011CDA4EFA007D6C76 /* ASDisplayTraits.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9C8221951BA237B80037F19A /* ASStackBaselinePositionedLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C8221931BA237B80037F19A /* ASStackBaselinePositionedLayout.h */; }; 9C8221961BA237B80037F19A /* ASStackBaselinePositionedLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C8221931BA237B80037F19A /* ASStackBaselinePositionedLayout.h */; }; 9C8221971BA237B80037F19A /* ASStackBaselinePositionedLayout.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9C8221941BA237B80037F19A /* ASStackBaselinePositionedLayout.mm */; }; @@ -801,6 +805,8 @@ 9C5586671BD549CB00B50E3A /* ASAsciiArtBoxCreator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASAsciiArtBoxCreator.h; path = AsyncDisplayKit/Layout/ASAsciiArtBoxCreator.h; sourceTree = ""; }; 9C5586681BD549CB00B50E3A /* ASAsciiArtBoxCreator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ASAsciiArtBoxCreator.m; path = AsyncDisplayKit/Layout/ASAsciiArtBoxCreator.m; sourceTree = ""; }; 9C6BB3B01B8CC9C200F13F52 /* ASStaticLayoutable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASStaticLayoutable.h; path = AsyncDisplayKit/Layout/ASStaticLayoutable.h; sourceTree = ""; }; + 9C70F2011CDA4EFA007D6C76 /* ASDisplayTraits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASDisplayTraits.h; sourceTree = ""; }; + 9C70F2021CDA4EFA007D6C76 /* ASDisplayTraits.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASDisplayTraits.m; sourceTree = ""; }; 9C8221931BA237B80037F19A /* ASStackBaselinePositionedLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASStackBaselinePositionedLayout.h; sourceTree = ""; }; 9C8221941BA237B80037F19A /* ASStackBaselinePositionedLayout.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASStackBaselinePositionedLayout.mm; sourceTree = ""; }; 9C8898BA1C738B9800D6B02E /* ASTextKitFontSizeAdjuster.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ASTextKitFontSizeAdjuster.mm; path = TextKit/ASTextKitFontSizeAdjuster.mm; sourceTree = ""; }; @@ -1223,6 +1229,8 @@ 205F0E0D1B371875007741D0 /* UICollectionViewLayout+ASConvenience.h */, 205F0E0E1B371875007741D0 /* UICollectionViewLayout+ASConvenience.m */, 058D09FF195D050800B7D73C /* UIView+ASConvenience.h */, + 9C70F2011CDA4EFA007D6C76 /* ASDisplayTraits.h */, + 9C70F2021CDA4EFA007D6C76 /* ASDisplayTraits.m */, ); path = Details; sourceTree = ""; @@ -1520,6 +1528,7 @@ 257754A81BEE44CD00737CA5 /* ASTextKitContext.h in Headers */, DB55C2611C6408D6004EDCF5 /* _ASTransitionContext.h in Headers */, 464052221A3F83C40061C0BA /* ASFlowLayoutController.h in Headers */, + 9C70F2031CDA4EFA007D6C76 /* ASDisplayTraits.h in Headers */, 257754AF1BEE44CD00737CA5 /* ASTextKitRenderer+TextChecking.h in Headers */, 058D0A57195D05DC00B7D73C /* ASHighlightOverlayLayer.h in Headers */, 058D0A7C195D05F900B7D73C /* ASImageNode+CGExtras.h in Headers */, @@ -1656,6 +1665,7 @@ 34EFC75B1B701BAF00AD841F /* ASDimension.h in Headers */, A37320101C571B740011FC94 /* ASTextNode+Beta.h in Headers */, DBABFAFC1C6A8D2F0039EA4A /* _ASTransitionContext.h in Headers */, + 9C70F2061CDA4F0C007D6C76 /* ASDisplayTraits.h in Headers */, 254C6B801BF94DF4003EC431 /* ASEqualityHashHelpers.h in Headers */, B350624F1B010EFD0018CF92 /* ASDisplayNode+DebugTiming.h in Headers */, B35061FD1B010EFD0018CF92 /* ASDisplayNode+Subclasses.h in Headers */, @@ -2043,6 +2053,7 @@ ACF6ED521B17847A00DA7C62 /* ASStackUnpositionedLayout.mm in Sources */, 257754A61BEE44CD00737CA5 /* ASTextKitAttributes.mm in Sources */, 81EE38501C8E94F000456208 /* ASRunLoopQueue.mm in Sources */, + 9C70F2041CDA4EFA007D6C76 /* ASDisplayTraits.m in Sources */, 92074A691CC8BADA00918F75 /* ASControlNode+tvOS.m in Sources */, ACF6ED321B17843500DA7C62 /* ASStaticLayoutSpec.mm in Sources */, AC026B6B1BD57D6F00BBC17E /* ASChangeSetDataController.m in Sources */, @@ -2193,6 +2204,7 @@ 34EFC7721B701D0300AD841F /* ASStackLayoutSpec.mm in Sources */, 34EFC7761B701D2A00AD841F /* ASStackPositionedLayout.mm in Sources */, 7AB338661C55B3420055FDE8 /* ASRelativeLayoutSpec.mm in Sources */, + 9C70F2051CDA4F06007D6C76 /* ASDisplayTraits.m in Sources */, 34EFC7781B701D3100AD841F /* ASStackUnpositionedLayout.mm in Sources */, DE84918E1C8FFF9F003D89E9 /* ASRunLoopQueue.mm in Sources */, AC026B6C1BD57D6F00BBC17E /* ASChangeSetDataController.m in Sources */, diff --git a/AsyncDisplayKit/ASDisplayNode.mm b/AsyncDisplayKit/ASDisplayNode.mm index 8ee237f50b..e1907f0fa9 100644 --- a/AsyncDisplayKit/ASDisplayNode.mm +++ b/AsyncDisplayKit/ASDisplayNode.mm @@ -22,6 +22,7 @@ #import "_ASCoreAnimationExtras.h" #import "ASDisplayNodeLayoutContext.h" #import "ASDisplayNodeExtras.h" +#import "ASDisplayTraits.h" #import "ASEqualityHelpers.h" #import "ASRunLoopQueue.h" #import "ASEnvironmentInternal.h" @@ -2720,6 +2721,11 @@ static const char *ASDisplayNodeDrawingPriorityKey = "ASDrawingPriority"; ASEnvironmentLayoutOptionsForwarding ASEnvironmentLayoutExtensibilityForwarding +- (ASDisplayTraits *)displayTraits +{ + ASDN::MutexLocker l(_propertyLock); + return [ASDisplayTraits displayTraitsWithASEnvironmentDisplayTraits:_environmentState.displayTraits]; +} #if TARGET_OS_TV #pragma mark - UIFocusEnvironment Protocol (tvOS) diff --git a/AsyncDisplayKit/ASViewController.h b/AsyncDisplayKit/ASViewController.h index fda6adb12d..e1b43342ec 100644 --- a/AsyncDisplayKit/ASViewController.h +++ b/AsyncDisplayKit/ASViewController.h @@ -9,10 +9,12 @@ #import #import +@class ASDisplayTraits; + NS_ASSUME_NONNULL_BEGIN -typedef ASEnvironmentDisplayTraits (^ASEnvironmentDisplayTraitsForTraitCollectionBlock)(UITraitCollection *traitCollection); -typedef ASEnvironmentDisplayTraits (^ASEnvironmentDisplayTraitsForTraitWindowSizeBlock)(CGSize windowSize); +typedef ASDisplayTraits * _Nonnull (^ASDisplayTraitsForTraitCollectionBlock)(UITraitCollection *traitCollection); +typedef ASDisplayTraits * _Nonnull (^ASDisplayTraitsForTraitWindowSizeBlock)(CGSize windowSize); @interface ASViewController<__covariant DisplayNodeType : ASDisplayNode *> : UIViewController @@ -25,12 +27,12 @@ typedef ASEnvironmentDisplayTraits (^ASEnvironmentDisplayTraitsForTraitWindowSiz /** * Set this block to customize the ASDisplayTraits returned when the VC transitions to the given traitCollection. */ -@property (nonatomic, copy) ASEnvironmentDisplayTraitsForTraitCollectionBlock overrideDisplayTraitsWithTraitCollection; +@property (nonatomic, copy) ASDisplayTraitsForTraitCollectionBlock overrideDisplayTraitsWithTraitCollection; /** * Set this block to customize the ASDisplayTraits returned when the VC transitions to the given window size. */ -@property (nonatomic, copy) ASEnvironmentDisplayTraitsForTraitWindowSizeBlock overrideDisplayTraitsWithWindowSize; +@property (nonatomic, copy) ASDisplayTraitsForTraitWindowSizeBlock overrideDisplayTraitsWithWindowSize; /** * @abstract Passthrough property to the the .interfaceState of the node. diff --git a/AsyncDisplayKit/ASViewController.mm b/AsyncDisplayKit/ASViewController.mm index 6643cdcb7b..b4834581de 100644 --- a/AsyncDisplayKit/ASViewController.mm +++ b/AsyncDisplayKit/ASViewController.mm @@ -11,6 +11,7 @@ #import "ASDimension.h" #import "ASDisplayNode+FrameworkPrivate.h" #import "ASDisplayNode+Beta.h" +#import "ASDisplayTraits.h" #import "ASEnvironmentInternal.h" #import "ASRangeControllerUpdateRangeProtocol+Beta.h" @@ -146,7 +147,9 @@ - (ASEnvironmentDisplayTraits)displayTraitsForTraitCollection:(UITraitCollection *)traitCollection { if (self.overrideDisplayTraitsWithTraitCollection) { - return self.overrideDisplayTraitsWithTraitCollection(traitCollection); + ASDisplayTraits *displayTraits = self.overrideDisplayTraitsWithTraitCollection(traitCollection); + displayTraits.isMutable = NO; + return [displayTraits environmentDisplayTraits]; } ASEnvironmentDisplayTraits displayTraits = ASEnvironmentDisplayTraitsFromUITraitCollection(traitCollection); @@ -157,7 +160,9 @@ - (ASEnvironmentDisplayTraits)displayTraitsForWindowSize:(CGSize)windowSize { if (self.overrideDisplayTraitsWithWindowSize) { - return self.overrideDisplayTraitsWithWindowSize(windowSize); + ASDisplayTraits *displayTraits = self.overrideDisplayTraitsWithWindowSize(windowSize); + displayTraits.isMutable = NO; + return [displayTraits environmentDisplayTraits]; } return self.node.environmentState.displayTraits; } diff --git a/AsyncDisplayKit/Details/ASDisplayTraits.h b/AsyncDisplayKit/Details/ASDisplayTraits.h new file mode 100644 index 0000000000..983487d2b0 --- /dev/null +++ b/AsyncDisplayKit/Details/ASDisplayTraits.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import +#import + +@interface ASDisplayTraits : NSObject + +@property (nonatomic, assign) BOOL isMutable; + +@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; + ++ (ASDisplayTraits *)displayTraitsWithASEnvironmentDisplayTraits:(ASEnvironmentDisplayTraits)traits; ++ (ASDisplayTraits *)displayTraitsWithUITraitCollection:(UITraitCollection *)traitCollection; + +- (ASEnvironmentDisplayTraits)environmentDisplayTraits; + +@end diff --git a/AsyncDisplayKit/Details/ASDisplayTraits.m b/AsyncDisplayKit/Details/ASDisplayTraits.m new file mode 100644 index 0000000000..77478cb672 --- /dev/null +++ b/AsyncDisplayKit/Details/ASDisplayTraits.m @@ -0,0 +1,91 @@ +// +// ASDisplayTraits.m +// AsyncDisplayKit +// +// Created by Ricky Cancro on 5/4/16. +// Copyright © 2016 Facebook. All rights reserved. +// + +#import "ASDisplayTraits.h" +#import +#import + +@implementation ASDisplayTraits + +- (instancetype)init +{ + self = [super init]; + if (self) { + _isMutable = YES; + } + return self; +} + +- (void)setDisplayScale:(CGFloat)displayScale +{ + ASDisplayNodeAssert(self.isMutable, @"ASDisplayTraits is no longer mutable"); + _displayScale = displayScale; +} + +- (void)setHorizontalSizeClass:(UIUserInterfaceSizeClass)horizontalSizeClass +{ + ASDisplayNodeAssert(self.isMutable, @"ASDisplayTraits is no longer mutable"); + _horizontalSizeClass = horizontalSizeClass; +} + +- (void)setUserInterfaceIdiom:(UIUserInterfaceIdiom)userInterfaceIdiom +{ + 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; +} + ++ (ASDisplayTraits *)displayTraitsWithASEnvironmentDisplayTraits:(ASEnvironmentDisplayTraits)traits +{ + ASDisplayTraits *displayTraits = [[ASDisplayTraits alloc] init]; + displayTraits.displayScale = traits.displayScale; + displayTraits.horizontalSizeClass = traits.horizontalSizeClass; + displayTraits.verticalSizeClass = traits.verticalSizeClass; + displayTraits.userInterfaceIdiom = traits.userInterfaceIdiom; + displayTraits.forceTouchCapability = traits.forceTouchCapability; + return displayTraits; +} + ++ (ASDisplayTraits *)displayTraitsWithUITraitCollection:(UITraitCollection *)traitCollection +{ + ASDisplayTraits *displayTraits = [[ASDisplayTraits alloc] init]; + if (AS_AT_LEAST_IOS8) { + displayTraits.displayScale = traitCollection.displayScale; + displayTraits.horizontalSizeClass = traitCollection.horizontalSizeClass; + displayTraits.verticalSizeClass = traitCollection.verticalSizeClass; + displayTraits.userInterfaceIdiom = traitCollection.userInterfaceIdiom; + if (AS_AT_LEAST_IOS9) { + displayTraits.forceTouchCapability = traitCollection.forceTouchCapability; + } + } + return displayTraits; +} + +- (ASEnvironmentDisplayTraits)environmentDisplayTraits +{ + return (ASEnvironmentDisplayTraits) { + .displayScale = self.displayScale, + .horizontalSizeClass = self.horizontalSizeClass, + .userInterfaceIdiom = self.userInterfaceIdiom, + .verticalSizeClass = self.verticalSizeClass, + .forceTouchCapability = self.forceTouchCapability, + }; +} + +@end diff --git a/AsyncDisplayKit/Details/ASEnvironment.h b/AsyncDisplayKit/Details/ASEnvironment.h index 7f11925cd5..ff24ac0021 100644 --- a/AsyncDisplayKit/Details/ASEnvironment.h +++ b/AsyncDisplayKit/Details/ASEnvironment.h @@ -76,15 +76,14 @@ typedef struct ASEnvironmentDisplayTraits { // sure that it is valid. // // Use displayContext when you wish to pass view context specific data along with the - // trait collcetion to subnodes. This should be a piece of data owned by an + // 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. // - // An added precaution is to call ASDisplayTraitsClearDisplayContext from your ASVC's desctructor + // As an added precaution ASDisplayTraitsClearDisplayContext is called from ASVC's desctructor // which will propagate a nil displayContext to its subnodes. - //__unsafe_unretained id displayContext; id __unsafe_unretained displayContext; } ASEnvironmentDisplayTraits; @@ -104,7 +103,7 @@ extern ASEnvironmentState ASEnvironmentStateMakeDefault(); ASDISPLAYNODE_EXTERN_C_END -@class ASTraitCollection; +@class ASDisplayTraits; #pragma mark - ASEnvironment @@ -131,6 +130,9 @@ ASDISPLAYNODE_EXTERN_C_END /// Classes should implement this method and return YES / NO dependent if downware propagation is enabled or not - (BOOL)supportsTraitsCollectionPropagation; +/// Returns an NSObject-representation of the environment's ASEnvironmentDisplayTraits +- (ASDisplayTraits *)displayTraits; + @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 d57663d90e..c8b90acdfa 100644 --- a/AsyncDisplayKit/Details/ASEnvironment.mm +++ b/AsyncDisplayKit/Details/ASEnvironment.mm @@ -10,6 +10,7 @@ #import "ASEnvironment.h" #import "ASEnvironmentInternal.h" +#import ASEnvironmentLayoutOptionsState _ASEnvironmentLayoutOptionsStateMakeDefault() { @@ -46,14 +47,18 @@ ASEnvironmentDisplayTraits _ASEnvironmentDisplayTraitsMakeDefault() } ASEnvironmentDisplayTraits ASEnvironmentDisplayTraitsFromUITraitCollection(UITraitCollection *traitCollection) -{ - return (ASEnvironmentDisplayTraits) { - .displayScale = traitCollection.displayScale, - .horizontalSizeClass = traitCollection.horizontalSizeClass, - .userInterfaceIdiom = traitCollection.userInterfaceIdiom, - .verticalSizeClass = traitCollection.verticalSizeClass, - .forceTouchCapability = traitCollection.forceTouchCapability, - }; +{ + ASEnvironmentDisplayTraits displayTraits; + if (AS_AT_LEAST_IOS8) { + displayTraits.displayScale = traitCollection.displayScale; + displayTraits.horizontalSizeClass = traitCollection.horizontalSizeClass; + displayTraits.verticalSizeClass = traitCollection.verticalSizeClass; + displayTraits.userInterfaceIdiom = traitCollection.userInterfaceIdiom; + if (AS_AT_LEAST_IOS9) { + displayTraits.forceTouchCapability = traitCollection.forceTouchCapability; + } + } + return displayTraits; } BOOL ASEnvironmentDisplayTraitsIsEqualToASEnvironmentDisplayTraits(ASEnvironmentDisplayTraits displayTraits0, ASEnvironmentDisplayTraits displayTraits1) diff --git a/AsyncDisplayKit/Layout/ASLayoutSpec.mm b/AsyncDisplayKit/Layout/ASLayoutSpec.mm index dc15ac2916..ef1a32cb2b 100644 --- a/AsyncDisplayKit/Layout/ASLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASLayoutSpec.mm @@ -12,6 +12,7 @@ #import "ASAssert.h" #import "ASBaseDefines.h" +#import "ASDisplayTraits.h" #import "ASEnvironmentInternal.h" #import "ASInternalHelpers.h" @@ -203,6 +204,12 @@ ASEnvironmentLayoutOptionsForwarding ASEnvironmentLayoutExtensibilityForwarding +- (ASDisplayTraits *)displayTraits +{ + ASDN::MutexLocker l(_propertyLock); + return [ASDisplayTraits displayTraitsWithASEnvironmentDisplayTraits:_environmentState.displayTraits]; +} + @end @implementation ASLayoutSpec (Debugging) diff --git a/Base/ASAvailability.h b/Base/ASAvailability.h index 78293c3d63..65fe04d647 100644 --- a/Base/ASAvailability.h +++ b/Base/ASAvailability.h @@ -23,6 +23,10 @@ #define kCFCoreFoundationVersionNumber_iOS_8_0 1140.1 #endif +#ifndef kCFCoreFoundationVersionNumber_iOS_8_4 +#define kCFCoreFoundationVersionNumber_iOS_8_4 1145.15 +#endif + #ifndef __IPHONE_7_0 #define __IPHONE_7_0 70000 #endif @@ -31,6 +35,10 @@ #define __IPHONE_8_0 80000 #endif +#ifndef __IPHONE_9_0 +#define __IPHONE_9_0 90000 +#endif + #ifndef AS_IOS8_SDK_OR_LATER #define AS_IOS8_SDK_OR_LATER __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_8_0 #endif @@ -38,3 +46,4 @@ #define AS_AT_LEAST_IOS7 (kCFCoreFoundationVersionNumber > kCFCoreFoundationVersionNumber_iOS_6_1) #define AS_AT_LEAST_IOS7_1 (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_7_1) #define AS_AT_LEAST_IOS8 (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_8_0) +#define AS_AT_LEAST_IOS9 (kCFCoreFoundationVersionNumber > kCFCoreFoundationVersionNumber_iOS_8_4) diff --git a/examples/DisplayTraits/Sample/CollectionViewController.m b/examples/DisplayTraits/Sample/CollectionViewController.m index 66e7b92adc..018aac6e96 100644 --- a/examples/DisplayTraits/Sample/CollectionViewController.m +++ b/examples/DisplayTraits/Sample/CollectionViewController.m @@ -11,6 +11,7 @@ #import "CollectionViewController.h" #import "KittenNode.h" +#import @interface CollectionViewController () @property (nonatomic, strong) ASCollectionNode *collectionNode; @@ -61,7 +62,7 @@ - (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath { - ASEnvironmentDisplayTraits displayTraits = self.collectionNode.environmentState.displayTraits; + ASDisplayTraits *displayTraits = [self.collectionNode displayTraits]; if (displayTraits.horizontalSizeClass == UIUserInterfaceSizeClassRegular) { return ASSizeRangeMake(CGSizeMake(200, 120), CGSizeMake(200, 120)); diff --git a/examples/DisplayTraits/Sample/KittenNode.m b/examples/DisplayTraits/Sample/KittenNode.m index dd8fbc4b96..8139292840 100644 --- a/examples/DisplayTraits/Sample/KittenNode.m +++ b/examples/DisplayTraits/Sample/KittenNode.m @@ -12,6 +12,8 @@ #import "KittenNode.h" #import "OverrideViewController.h" +#import + static const CGFloat kOuterPadding = 16.0f; static const CGFloat kInnerPadding = 10.0f; @@ -128,8 +130,7 @@ static const CGFloat kInnerPadding = 10.0f; - (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize { - - ASEnvironmentDisplayTraits displayTraits = self.environmentState.displayTraits; + ASDisplayTraits *displayTraits = [self displayTraits]; ASStackLayoutSpec *stackSpec = [[ASStackLayoutSpec alloc] init]; stackSpec.spacing = kInnerPadding; @@ -146,19 +147,15 @@ static const CGFloat kInnerPadding = 10.0f; return [ASInsetLayoutSpec insetLayoutSpecWithInsets:UIEdgeInsetsMake(kOuterPadding, kOuterPadding, kOuterPadding, kOuterPadding) child:stackSpec]; } - + (void)defaultImageTappedAction:(ASViewController *)sourceViewController { OverrideViewController *overrideVC = [[OverrideViewController alloc] init]; overrideVC.overrideDisplayTraitsWithTraitCollection = ^(UITraitCollection *traitCollection) { - return (ASEnvironmentDisplayTraits) { - .displayScale = traitCollection.displayScale, - .horizontalSizeClass = UIUserInterfaceSizeClassCompact, - .userInterfaceIdiom = traitCollection.userInterfaceIdiom, - .verticalSizeClass = UIUserInterfaceSizeClassCompact, - .forceTouchCapability = traitCollection.forceTouchCapability, - }; + ASDisplayTraits *displayTraits = [ASDisplayTraits displayTraitsWithUITraitCollection:traitCollection]; + displayTraits.horizontalSizeClass = UIUserInterfaceSizeClassCompact; + displayTraits.verticalSizeClass = UIUserInterfaceSizeClassCompact; + return displayTraits; }; [sourceViewController presentViewController:overrideVC animated:YES completion:nil]; diff --git a/examples/DisplayTraits/Sample/OverrideViewController.m b/examples/DisplayTraits/Sample/OverrideViewController.m index b0024b38e7..6a99e76a53 100644 --- a/examples/DisplayTraits/Sample/OverrideViewController.m +++ b/examples/DisplayTraits/Sample/OverrideViewController.m @@ -10,6 +10,8 @@ */ #import "OverrideViewController.h" +#import + static NSString *kLinkAttributeName = @"PlaceKittenNodeLinkAttributeName"; @interface OverrideNode() @@ -42,7 +44,7 @@ static NSString *kLinkAttributeName = @"PlaceKittenNodeLinkAttributeName"; - (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize { CGFloat pointSize = 16.f; - ASEnvironmentDisplayTraits displayTraits = self.environmentState.displayTraits; + ASDisplayTraits *displayTraits = [self displayTraits]; if (displayTraits.horizontalSizeClass == UIUserInterfaceSizeClassRegular) { // This should never happen because we override the VC's display traits to always be compact. pointSize = 100; From a04cbb6e4f41bca7d185a5a1a6c057ca30171959 Mon Sep 17 00:00:00 2001 From: rcancro Date: Wed, 4 May 2016 13:09:34 -0700 Subject: [PATCH 23/52] include displayContext in equality check --- AsyncDisplayKit/Details/ASEnvironment.mm | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/AsyncDisplayKit/Details/ASEnvironment.mm b/AsyncDisplayKit/Details/ASEnvironment.mm index c8b90acdfa..c9c7afc68a 100644 --- a/AsyncDisplayKit/Details/ASEnvironment.mm +++ b/AsyncDisplayKit/Details/ASEnvironment.mm @@ -64,11 +64,12 @@ ASEnvironmentDisplayTraits ASEnvironmentDisplayTraitsFromUITraitCollection(UITra BOOL ASEnvironmentDisplayTraitsIsEqualToASEnvironmentDisplayTraits(ASEnvironmentDisplayTraits displayTraits0, ASEnvironmentDisplayTraits displayTraits1) { return - displayTraits0.verticalSizeClass == displayTraits1.verticalSizeClass && - displayTraits0.horizontalSizeClass == displayTraits1.horizontalSizeClass && - displayTraits0.displayScale == displayTraits1.displayScale && - displayTraits0.userInterfaceIdiom == displayTraits1.userInterfaceIdiom && - displayTraits0.forceTouchCapability == displayTraits1.forceTouchCapability; + displayTraits0.verticalSizeClass == displayTraits1.verticalSizeClass && + displayTraits0.horizontalSizeClass == displayTraits1.horizontalSizeClass && + displayTraits0.displayScale == displayTraits1.displayScale && + displayTraits0.userInterfaceIdiom == displayTraits1.userInterfaceIdiom && + displayTraits0.forceTouchCapability == displayTraits1.forceTouchCapability && + displayTraits0.displayContext == displayTraits1.displayContext; } ASEnvironmentState ASEnvironmentStateMakeDefault() From 223a5f04b1284b7c5f6da7d076ad53d377f66fc9 Mon Sep 17 00:00:00 2001 From: rcancro Date: Wed, 4 May 2016 14:57:21 -0700 Subject: [PATCH 24/52] fix build errors --- AsyncDisplayKit.xcodeproj/project.pbxproj | 2 ++ .../BackgroundPropertySetting/Sample/ViewController.swift | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index 096b77cefe..45ec8021a2 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -328,6 +328,7 @@ 9C70F2041CDA4EFA007D6C76 /* ASDisplayTraits.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C70F2021CDA4EFA007D6C76 /* ASDisplayTraits.m */; }; 9C70F2051CDA4F06007D6C76 /* ASDisplayTraits.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C70F2021CDA4EFA007D6C76 /* ASDisplayTraits.m */; }; 9C70F2061CDA4F0C007D6C76 /* ASDisplayTraits.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C70F2011CDA4EFA007D6C76 /* ASDisplayTraits.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9C70F2081CDAA3C6007D6C76 /* ASEnvironment.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9CFFC6BD1CCAC52B006A6476 /* ASEnvironment.mm */; }; 9C8221951BA237B80037F19A /* ASStackBaselinePositionedLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C8221931BA237B80037F19A /* ASStackBaselinePositionedLayout.h */; }; 9C8221961BA237B80037F19A /* ASStackBaselinePositionedLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C8221931BA237B80037F19A /* ASStackBaselinePositionedLayout.h */; }; 9C8221971BA237B80037F19A /* ASStackBaselinePositionedLayout.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9C8221941BA237B80037F19A /* ASStackBaselinePositionedLayout.mm */; }; @@ -2140,6 +2141,7 @@ 9C8898BC1C738BA800D6B02E /* ASTextKitFontSizeAdjuster.mm in Sources */, 34EFC7621B701CA400AD841F /* ASBackgroundLayoutSpec.mm in Sources */, DE8BEAC41C2DF3FC00D57C12 /* ASDelegateProxy.m in Sources */, + 9C70F2081CDAA3C6007D6C76 /* ASEnvironment.mm in Sources */, B35062141B010EFD0018CF92 /* ASBasicImageDownloader.mm in Sources */, B35062161B010EFD0018CF92 /* ASBatchContext.mm in Sources */, AC47D9421B3B891B00AAEE9D /* ASCellNode.mm in Sources */, diff --git a/examples/BackgroundPropertySetting/Sample/ViewController.swift b/examples/BackgroundPropertySetting/Sample/ViewController.swift index 1573b9ebeb..88edf7813d 100644 --- a/examples/BackgroundPropertySetting/Sample/ViewController.swift +++ b/examples/BackgroundPropertySetting/Sample/ViewController.swift @@ -24,8 +24,8 @@ final class ViewController: ASViewController, ASCollectionDelegate, ASCollection layout.minimumInteritemSpacing = padding layout.minimumLineSpacing = padding super.init(node: ASCollectionNode(collectionViewLayout: layout)) - navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Color", style: .Plain, target: self, action: "didTapColorsButton") - navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Layout", style: .Plain, target: self, action: "didTapLayoutButton") + navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Color", style: .Plain, target: self, action: #selector(didTapColorsButton)) + navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Layout", style: .Plain, target: self, action: #selector(didTapLayoutButton)) collectionNode.delegate = self collectionNode.dataSource = self title = "Background Updating" From 51f79f3c6e2cd786b948f662f6036d6b48066fc5 Mon Sep 17 00:00:00 2001 From: rcancro Date: Wed, 4 May 2016 16:17:55 -0700 Subject: [PATCH 25/52] fix build? --- AsyncDisplayKit.xcodeproj/project.pbxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index 45ec8021a2..5ba63ba7ce 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -329,6 +329,7 @@ 9C70F2051CDA4F06007D6C76 /* ASDisplayTraits.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C70F2021CDA4EFA007D6C76 /* ASDisplayTraits.m */; }; 9C70F2061CDA4F0C007D6C76 /* ASDisplayTraits.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C70F2011CDA4EFA007D6C76 /* ASDisplayTraits.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9C70F2081CDAA3C6007D6C76 /* ASEnvironment.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9CFFC6BD1CCAC52B006A6476 /* ASEnvironment.mm */; }; + 9C70F2091CDABA36007D6C76 /* ASViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9CFFC6BF1CCAC73C006A6476 /* ASViewController.mm */; }; 9C8221951BA237B80037F19A /* ASStackBaselinePositionedLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C8221931BA237B80037F19A /* ASStackBaselinePositionedLayout.h */; }; 9C8221961BA237B80037F19A /* ASStackBaselinePositionedLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C8221931BA237B80037F19A /* ASStackBaselinePositionedLayout.h */; }; 9C8221971BA237B80037F19A /* ASStackBaselinePositionedLayout.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9C8221941BA237B80037F19A /* ASStackBaselinePositionedLayout.mm */; }; @@ -2118,6 +2119,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 9C70F2091CDABA36007D6C76 /* ASViewController.mm in Sources */, DE4843DB1C93EAB100A1F33B /* ASDisplayNodeLayoutContext.mm in Sources */, B30BF6541C59D889004FCD53 /* ASLayoutManager.m in Sources */, 92DD2FE71BF4D0850074C9DD /* ASMapNode.mm in Sources */, From 9d622c7eac5181aa945ec9f6bf733b927df1529e Mon Sep 17 00:00:00 2001 From: rcancro Date: Thu, 5 May 2016 14:01:19 -0700 Subject: [PATCH 26/52] changed DisplayTraits to TraitCollection --- AsyncDisplayKit.xcodeproj/project.pbxproj | 48 ++++++++++------- ...ASCollectionNode.mm => ASCollectionNode.m} | 2 +- AsyncDisplayKit/ASDisplayNode.mm | 6 +-- AsyncDisplayKit/ASTableNode.mm | 2 +- AsyncDisplayKit/ASViewController.h | 6 +-- AsyncDisplayKit/ASViewController.mm | 52 +++++++++---------- AsyncDisplayKit/Details/ASDataController.mm | 2 +- AsyncDisplayKit/Details/ASEnvironment.h | 26 +++++----- AsyncDisplayKit/Details/ASEnvironment.mm | 42 +++++++-------- ...{ASDisplayTraits.h => ASTraitCollection.h} | 8 +-- ...{ASDisplayTraits.m => ASTraitCollection.m} | 40 +++++++------- AsyncDisplayKit/Layout/ASLayoutSpec.mm | 6 +-- .../Private/ASEnvironmentInternal.h | 4 +- .../Private/ASEnvironmentInternal.mm | 18 +++---- .../contents.xcworkspacedata | 0 .../Podfile | 0 .../Sample.xcodeproj/project.pbxproj | 0 .../contents.xcworkspacedata | 0 .../xcshareddata/xcschemes/Sample.xcscheme | 0 .../contents.xcworkspacedata | 10 ++++ .../Sample/AppDelegate.h | 0 .../Sample/AppDelegate.m | 0 .../Sample/CollectionViewController.h | 0 .../Sample/CollectionViewController.m | 6 +-- .../Sample/Info.plist | 0 .../Sample/KittenNode.h | 0 .../Sample/KittenNode.m | 14 ++--- .../Sample/Launch Screen.storyboard | 0 .../Sample/OverrideViewController.h | 0 .../Sample/OverrideViewController.m | 6 +-- .../Sample/TableViewController.h | 0 .../Sample/TableViewController.m | 0 .../Sample/ViewController.h | 0 .../Sample/ViewController.m | 0 .../Sample/main.m | 0 35 files changed, 160 insertions(+), 138 deletions(-) rename AsyncDisplayKit/{ASCollectionNode.mm => ASCollectionNode.m} (98%) rename AsyncDisplayKit/Details/{ASDisplayTraits.h => ASTraitCollection.h} (72%) rename AsyncDisplayKit/Details/{ASDisplayTraits.m => ASTraitCollection.m} (56%) rename examples/{DisplayTraits => ASCollectionView}/Sample.xcworkspace/contents.xcworkspacedata (100%) rename examples/{DisplayTraits => ASTraitCollection}/Podfile (100%) rename examples/{DisplayTraits => ASTraitCollection}/Sample.xcodeproj/project.pbxproj (100%) rename examples/{DisplayTraits => ASTraitCollection}/Sample.xcodeproj/project.xcworkspace/contents.xcworkspacedata (100%) rename examples/{DisplayTraits => ASTraitCollection}/Sample.xcodeproj/xcshareddata/xcschemes/Sample.xcscheme (100%) create mode 100644 examples/ASTraitCollection/Sample.xcworkspace/contents.xcworkspacedata rename examples/{DisplayTraits => ASTraitCollection}/Sample/AppDelegate.h (100%) rename examples/{DisplayTraits => ASTraitCollection}/Sample/AppDelegate.m (100%) rename examples/{DisplayTraits => ASTraitCollection}/Sample/CollectionViewController.h (100%) rename examples/{DisplayTraits => ASTraitCollection}/Sample/CollectionViewController.m (91%) rename examples/{DisplayTraits => ASTraitCollection}/Sample/Info.plist (100%) rename examples/{DisplayTraits => ASTraitCollection}/Sample/KittenNode.h (100%) rename examples/{DisplayTraits => ASTraitCollection}/Sample/KittenNode.m (93%) rename examples/{DisplayTraits => ASTraitCollection}/Sample/Launch Screen.storyboard (100%) rename examples/{DisplayTraits => ASTraitCollection}/Sample/OverrideViewController.h (100%) rename examples/{DisplayTraits => ASTraitCollection}/Sample/OverrideViewController.m (94%) rename examples/{DisplayTraits => ASTraitCollection}/Sample/TableViewController.h (100%) rename examples/{DisplayTraits => ASTraitCollection}/Sample/TableViewController.m (100%) rename examples/{DisplayTraits => ASTraitCollection}/Sample/ViewController.h (100%) rename examples/{DisplayTraits => ASTraitCollection}/Sample/ViewController.m (100%) rename examples/{DisplayTraits => ASTraitCollection}/Sample/main.m (100%) diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index 5ba63ba7ce..f55ce2250a 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -111,8 +111,8 @@ 05F20AA41A15733C00DCA68A /* ASImageProtocols.h in Headers */ = {isa = PBXBuildFile; fileRef = 05F20AA31A15733C00DCA68A /* ASImageProtocols.h */; settings = {ATTRIBUTES = (Public, ); }; }; 18C2ED7E1B9B7DE800F627B3 /* ASCollectionNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 18C2ED7C1B9B7DE800F627B3 /* ASCollectionNode.h */; settings = {ATTRIBUTES = (Public, ); }; }; 18C2ED7F1B9B7DE800F627B3 /* ASCollectionNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 18C2ED7C1B9B7DE800F627B3 /* ASCollectionNode.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 18C2ED801B9B7DE800F627B3 /* ASCollectionNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = 18C2ED7D1B9B7DE800F627B3 /* ASCollectionNode.mm */; }; - 18C2ED831B9B7DE800F627B3 /* ASCollectionNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = 18C2ED7D1B9B7DE800F627B3 /* ASCollectionNode.mm */; }; + 18C2ED801B9B7DE800F627B3 /* ASCollectionNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 18C2ED7D1B9B7DE800F627B3 /* ASCollectionNode.m */; }; + 18C2ED831B9B7DE800F627B3 /* ASCollectionNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 18C2ED7D1B9B7DE800F627B3 /* ASCollectionNode.m */; }; 1950C4491A3BB5C1005C8279 /* ASEqualityHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 1950C4481A3BB5C1005C8279 /* ASEqualityHelpers.h */; settings = {ATTRIBUTES = (Public, ); }; }; 204C979E1B362CB3002B1083 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 204C979D1B362CB3002B1083 /* Default-568h@2x.png */; }; 205F0E0F1B371875007741D0 /* UICollectionViewLayout+ASConvenience.h in Headers */ = {isa = PBXBuildFile; fileRef = 205F0E0D1B371875007741D0 /* UICollectionViewLayout+ASConvenience.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -324,12 +324,18 @@ 9C55866C1BD54A3000B50E3A /* ASAsciiArtBoxCreator.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C5586671BD549CB00B50E3A /* ASAsciiArtBoxCreator.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9C6BB3B21B8CC9C200F13F52 /* ASStaticLayoutable.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C6BB3B01B8CC9C200F13F52 /* ASStaticLayoutable.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9C6BB3B31B8CC9C200F13F52 /* ASStaticLayoutable.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C6BB3B01B8CC9C200F13F52 /* ASStaticLayoutable.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 9C70F2031CDA4EFA007D6C76 /* ASDisplayTraits.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C70F2011CDA4EFA007D6C76 /* ASDisplayTraits.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 9C70F2041CDA4EFA007D6C76 /* ASDisplayTraits.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C70F2021CDA4EFA007D6C76 /* ASDisplayTraits.m */; }; - 9C70F2051CDA4F06007D6C76 /* ASDisplayTraits.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C70F2021CDA4EFA007D6C76 /* ASDisplayTraits.m */; }; - 9C70F2061CDA4F0C007D6C76 /* ASDisplayTraits.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C70F2011CDA4EFA007D6C76 /* ASDisplayTraits.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9C70F2031CDA4EFA007D6C76 /* ASTraitCollection.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C70F2011CDA4EFA007D6C76 /* ASTraitCollection.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9C70F2041CDA4EFA007D6C76 /* ASTraitCollection.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C70F2021CDA4EFA007D6C76 /* ASTraitCollection.m */; }; + 9C70F2051CDA4F06007D6C76 /* ASTraitCollection.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C70F2021CDA4EFA007D6C76 /* ASTraitCollection.m */; }; + 9C70F2061CDA4F0C007D6C76 /* ASTraitCollection.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C70F2011CDA4EFA007D6C76 /* ASTraitCollection.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9C70F2081CDAA3C6007D6C76 /* ASEnvironment.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9CFFC6BD1CCAC52B006A6476 /* ASEnvironment.mm */; }; 9C70F2091CDABA36007D6C76 /* ASViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9CFFC6BF1CCAC73C006A6476 /* ASViewController.mm */; }; + 9C70F20A1CDBE949007D6C76 /* ASTableNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9CFFC6C11CCAC768006A6476 /* ASTableNode.mm */; }; + 9C70F20B1CDBE9A4007D6C76 /* ASDataController+Subclasses.h in Headers */ = {isa = PBXBuildFile; fileRef = 251B8EF61BBB3D690087C538 /* ASDataController+Subclasses.h */; }; + 9C70F20C1CDBE9B6007D6C76 /* ASCollectionDataController.h in Headers */ = {isa = PBXBuildFile; fileRef = 251B8EF21BBB3D690087C538 /* ASCollectionDataController.h */; }; + 9C70F20D1CDBE9CB007D6C76 /* ASDefaultPlayButton.h in Headers */ = {isa = PBXBuildFile; fileRef = AEB7B0181C5962EA00662EF4 /* ASDefaultPlayButton.h */; }; + 9C70F20E1CDBE9E5007D6C76 /* NSArray+Diffing.h in Headers */ = {isa = PBXBuildFile; fileRef = DBC452D91C5BF64600B16017 /* NSArray+Diffing.h */; }; + 9C70F20F1CDBE9FF007D6C76 /* ASLayoutManager.h in Headers */ = {isa = PBXBuildFile; fileRef = B30BF6501C5964B0004FCD53 /* ASLayoutManager.h */; }; 9C8221951BA237B80037F19A /* ASStackBaselinePositionedLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C8221931BA237B80037F19A /* ASStackBaselinePositionedLayout.h */; }; 9C8221961BA237B80037F19A /* ASStackBaselinePositionedLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C8221931BA237B80037F19A /* ASStackBaselinePositionedLayout.h */; }; 9C8221971BA237B80037F19A /* ASStackBaselinePositionedLayout.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9C8221941BA237B80037F19A /* ASStackBaselinePositionedLayout.mm */; }; @@ -705,7 +711,7 @@ 05EA6FE61AC0966E00E35788 /* ASSnapshotTestCase.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASSnapshotTestCase.mm; sourceTree = ""; }; 05F20AA31A15733C00DCA68A /* ASImageProtocols.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASImageProtocols.h; sourceTree = ""; }; 18C2ED7C1B9B7DE800F627B3 /* ASCollectionNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASCollectionNode.h; sourceTree = ""; }; - 18C2ED7D1B9B7DE800F627B3 /* ASCollectionNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASCollectionNode.mm; sourceTree = ""; }; + 18C2ED7D1B9B7DE800F627B3 /* ASCollectionNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASCollectionNode.m; sourceTree = ""; }; 1950C4481A3BB5C1005C8279 /* ASEqualityHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASEqualityHelpers.h; sourceTree = ""; }; 204C979D1B362CB3002B1083 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Default-568h@2x.png"; path = "../Default-568h@2x.png"; sourceTree = ""; }; 205F0E0D1B371875007741D0 /* UICollectionViewLayout+ASConvenience.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UICollectionViewLayout+ASConvenience.h"; sourceTree = ""; }; @@ -807,8 +813,8 @@ 9C5586671BD549CB00B50E3A /* ASAsciiArtBoxCreator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASAsciiArtBoxCreator.h; path = AsyncDisplayKit/Layout/ASAsciiArtBoxCreator.h; sourceTree = ""; }; 9C5586681BD549CB00B50E3A /* ASAsciiArtBoxCreator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ASAsciiArtBoxCreator.m; path = AsyncDisplayKit/Layout/ASAsciiArtBoxCreator.m; sourceTree = ""; }; 9C6BB3B01B8CC9C200F13F52 /* ASStaticLayoutable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASStaticLayoutable.h; path = AsyncDisplayKit/Layout/ASStaticLayoutable.h; sourceTree = ""; }; - 9C70F2011CDA4EFA007D6C76 /* ASDisplayTraits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASDisplayTraits.h; sourceTree = ""; }; - 9C70F2021CDA4EFA007D6C76 /* ASDisplayTraits.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASDisplayTraits.m; sourceTree = ""; }; + 9C70F2011CDA4EFA007D6C76 /* ASTraitCollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASTraitCollection.h; sourceTree = ""; }; + 9C70F2021CDA4EFA007D6C76 /* ASTraitCollection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASTraitCollection.m; sourceTree = ""; }; 9C8221931BA237B80037F19A /* ASStackBaselinePositionedLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASStackBaselinePositionedLayout.h; sourceTree = ""; }; 9C8221941BA237B80037F19A /* ASStackBaselinePositionedLayout.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASStackBaselinePositionedLayout.mm; sourceTree = ""; }; 9C8898BA1C738B9800D6B02E /* ASTextKitFontSizeAdjuster.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ASTextKitFontSizeAdjuster.mm; path = TextKit/ASTextKitFontSizeAdjuster.mm; sourceTree = ""; }; @@ -1043,7 +1049,7 @@ 055F1A3A19ABD43F004DAFF1 /* ASCellNode.h */, AC6456071B0A335000CF11B8 /* ASCellNode.mm */, 18C2ED7C1B9B7DE800F627B3 /* ASCollectionNode.h */, - 18C2ED7D1B9B7DE800F627B3 /* ASCollectionNode.mm */, + 18C2ED7D1B9B7DE800F627B3 /* ASCollectionNode.m */, B13CA0FF1C52004900E031AB /* ASCollectionNode+Beta.h */, AC3C4A4F1A1139C100143C57 /* ASCollectionView.h */, AC3C4A501A1139C100143C57 /* ASCollectionView.mm */, @@ -1231,8 +1237,8 @@ 205F0E0D1B371875007741D0 /* UICollectionViewLayout+ASConvenience.h */, 205F0E0E1B371875007741D0 /* UICollectionViewLayout+ASConvenience.m */, 058D09FF195D050800B7D73C /* UIView+ASConvenience.h */, - 9C70F2011CDA4EFA007D6C76 /* ASDisplayTraits.h */, - 9C70F2021CDA4EFA007D6C76 /* ASDisplayTraits.m */, + 9C70F2011CDA4EFA007D6C76 /* ASTraitCollection.h */, + 9C70F2021CDA4EFA007D6C76 /* ASTraitCollection.m */, ); path = Details; sourceTree = ""; @@ -1530,7 +1536,7 @@ 257754A81BEE44CD00737CA5 /* ASTextKitContext.h in Headers */, DB55C2611C6408D6004EDCF5 /* _ASTransitionContext.h in Headers */, 464052221A3F83C40061C0BA /* ASFlowLayoutController.h in Headers */, - 9C70F2031CDA4EFA007D6C76 /* ASDisplayTraits.h in Headers */, + 9C70F2031CDA4EFA007D6C76 /* ASTraitCollection.h in Headers */, 257754AF1BEE44CD00737CA5 /* ASTextKitRenderer+TextChecking.h in Headers */, 058D0A57195D05DC00B7D73C /* ASHighlightOverlayLayer.h in Headers */, 058D0A7C195D05F900B7D73C /* ASImageNode+CGExtras.h in Headers */, @@ -1615,6 +1621,7 @@ B35062481B010EFD0018CF92 /* _AS-objc-internal.h in Headers */, 69F10C871C84C35D0026140C /* ASRangeControllerUpdateRangeProtocol+Beta.h in Headers */, B350623C1B010EFD0018CF92 /* _ASAsyncTransaction.h in Headers */, + 9C70F20D1CDBE9CB007D6C76 /* ASDefaultPlayButton.h in Headers */, 68355B411CB57A6C001D4E68 /* ASImageContainerProtocolCategories.h in Headers */, 7630FFA81C9E267E007A7C0E /* ASVideoNode.h in Headers */, B350623F1B010EFD0018CF92 /* _ASAsyncTransactionContainer.h in Headers */, @@ -1651,6 +1658,7 @@ AC026B701BD57DBF00BBC17E /* _ASHierarchyChangeSet.h in Headers */, B35061F31B010EFD0018CF92 /* ASCellNode.h in Headers */, 34EFC7631B701CBF00AD841F /* ASCenterLayoutSpec.h in Headers */, + 9C70F20C1CDBE9B6007D6C76 /* ASCollectionDataController.h in Headers */, 18C2ED7F1B9B7DE800F627B3 /* ASCollectionNode.h in Headers */, 9C8898BD1C738BB800D6B02E /* ASTextKitFontSizeAdjuster.h in Headers */, B35061F51B010EFD0018CF92 /* ASCollectionView.h in Headers */, @@ -1660,6 +1668,7 @@ 92074A621CC8BA1900918F75 /* ASImageNode+tvOS.h in Headers */, B35061F71B010EFD0018CF92 /* ASCollectionViewProtocols.h in Headers */, DE6EA3231C14000600183B10 /* ASDisplayNode+FrameworkPrivate.h in Headers */, + 9C70F20F1CDBE9FF007D6C76 /* ASLayoutManager.h in Headers */, B35061FA1B010EFD0018CF92 /* ASControlNode+Subclasses.h in Headers */, B35061F81B010EFD0018CF92 /* ASControlNode.h in Headers */, B35062171B010EFD0018CF92 /* ASDataController.h in Headers */, @@ -1667,7 +1676,7 @@ 34EFC75B1B701BAF00AD841F /* ASDimension.h in Headers */, A37320101C571B740011FC94 /* ASTextNode+Beta.h in Headers */, DBABFAFC1C6A8D2F0039EA4A /* _ASTransitionContext.h in Headers */, - 9C70F2061CDA4F0C007D6C76 /* ASDisplayTraits.h in Headers */, + 9C70F2061CDA4F0C007D6C76 /* ASTraitCollection.h in Headers */, 254C6B801BF94DF4003EC431 /* ASEqualityHashHelpers.h in Headers */, B350624F1B010EFD0018CF92 /* ASDisplayNode+DebugTiming.h in Headers */, B35061FD1B010EFD0018CF92 /* ASDisplayNode+Subclasses.h in Headers */, @@ -1686,6 +1695,7 @@ B35062021B010EFD0018CF92 /* ASImageNode.h in Headers */, B350621F1B010EFD0018CF92 /* ASImageProtocols.h in Headers */, 430E7C901B4C23F100697A4C /* ASIndexPath.h in Headers */, + 9C70F20B1CDBE9A4007D6C76 /* ASDataController+Subclasses.h in Headers */, 34EFC75F1B701C8600AD841F /* ASInsetLayoutSpec.h in Headers */, 34EFC75D1B701BE900AD841F /* ASInternalHelpers.h in Headers */, 34EFC7671B701CD900AD841F /* ASLayout.h in Headers */, @@ -1721,6 +1731,7 @@ 25E327571C16819500A2170C /* ASPagerNode.h in Headers */, B35062551B010EFD0018CF92 /* ASSentinel.h in Headers */, 9C8221961BA237B80037F19A /* ASStackBaselinePositionedLayout.h in Headers */, + 9C70F20E1CDBE9E5007D6C76 /* NSArray+Diffing.h in Headers */, 9C49C3701B853961000B0DD5 /* ASStackLayoutable.h in Headers */, DE040EF91C2B40AC004692FF /* ASCollectionViewFlowLayoutInspector.h in Headers */, 34EFC7701B701CFA00AD841F /* ASStackLayoutDefines.h in Headers */, @@ -1987,7 +1998,7 @@ AC6456091B0A335000CF11B8 /* ASCellNode.mm in Sources */, DE8BEAC31C2DF3FC00D57C12 /* ASDelegateProxy.m in Sources */, ACF6ED1D1B17843500DA7C62 /* ASCenterLayoutSpec.mm in Sources */, - 18C2ED801B9B7DE800F627B3 /* ASCollectionNode.mm in Sources */, + 18C2ED801B9B7DE800F627B3 /* ASCollectionNode.m in Sources */, 92DD2FE41BF4B97E0074C9DD /* ASMapNode.mm in Sources */, DBC452DC1C5BF64600B16017 /* NSArray+Diffing.m in Sources */, AC3C4A521A1139C100143C57 /* ASCollectionView.mm in Sources */, @@ -2055,7 +2066,7 @@ ACF6ED521B17847A00DA7C62 /* ASStackUnpositionedLayout.mm in Sources */, 257754A61BEE44CD00737CA5 /* ASTextKitAttributes.mm in Sources */, 81EE38501C8E94F000456208 /* ASRunLoopQueue.mm in Sources */, - 9C70F2041CDA4EFA007D6C76 /* ASDisplayTraits.m in Sources */, + 9C70F2041CDA4EFA007D6C76 /* ASTraitCollection.m in Sources */, 92074A691CC8BADA00918F75 /* ASControlNode+tvOS.m in Sources */, ACF6ED321B17843500DA7C62 /* ASStaticLayoutSpec.mm in Sources */, AC026B6B1BD57D6F00BBC17E /* ASChangeSetDataController.m in Sources */, @@ -2148,9 +2159,10 @@ B35062161B010EFD0018CF92 /* ASBatchContext.mm in Sources */, AC47D9421B3B891B00AAEE9D /* ASCellNode.mm in Sources */, 34EFC7641B701CC600AD841F /* ASCenterLayoutSpec.mm in Sources */, - 18C2ED831B9B7DE800F627B3 /* ASCollectionNode.mm in Sources */, + 18C2ED831B9B7DE800F627B3 /* ASCollectionNode.m in Sources */, E55D86331CA8A14000A0C26F /* ASLayoutable.mm in Sources */, 68B8A4E41CBDB958007E4543 /* ASWeakProxy.m in Sources */, + 9C70F20A1CDBE949007D6C76 /* ASTableNode.mm in Sources */, 69CB62AE1CB8165900024920 /* _ASDisplayViewAccessiblity.mm in Sources */, B35061F61B010EFD0018CF92 /* ASCollectionView.mm in Sources */, 509E68641B3AEDB7009B9150 /* ASCollectionViewLayoutController.mm in Sources */, @@ -2208,7 +2220,7 @@ 34EFC7721B701D0300AD841F /* ASStackLayoutSpec.mm in Sources */, 34EFC7761B701D2A00AD841F /* ASStackPositionedLayout.mm in Sources */, 7AB338661C55B3420055FDE8 /* ASRelativeLayoutSpec.mm in Sources */, - 9C70F2051CDA4F06007D6C76 /* ASDisplayTraits.m in Sources */, + 9C70F2051CDA4F06007D6C76 /* ASTraitCollection.m in Sources */, 34EFC7781B701D3100AD841F /* ASStackUnpositionedLayout.mm in Sources */, DE84918E1C8FFF9F003D89E9 /* ASRunLoopQueue.mm in Sources */, AC026B6C1BD57D6F00BBC17E /* ASChangeSetDataController.m in Sources */, diff --git a/AsyncDisplayKit/ASCollectionNode.mm b/AsyncDisplayKit/ASCollectionNode.m similarity index 98% rename from AsyncDisplayKit/ASCollectionNode.mm rename to AsyncDisplayKit/ASCollectionNode.m index 15a19658c9..e5c7880f48 100644 --- a/AsyncDisplayKit/ASCollectionNode.mm +++ b/AsyncDisplayKit/ASCollectionNode.m @@ -248,6 +248,6 @@ [self.view reloadDataImmediately]; } -ASEnvironmentDisplayTraitsCollectionTableSetEnvironmentState(_environmentStateLock) +ASEnvironmentCollectionTableSetEnvironmentState(_environmentStateLock) @end diff --git a/AsyncDisplayKit/ASDisplayNode.mm b/AsyncDisplayKit/ASDisplayNode.mm index e1907f0fa9..2e04ba499c 100644 --- a/AsyncDisplayKit/ASDisplayNode.mm +++ b/AsyncDisplayKit/ASDisplayNode.mm @@ -22,7 +22,7 @@ #import "_ASCoreAnimationExtras.h" #import "ASDisplayNodeLayoutContext.h" #import "ASDisplayNodeExtras.h" -#import "ASDisplayTraits.h" +#import "ASTraitCollection.h" #import "ASEqualityHelpers.h" #import "ASRunLoopQueue.h" #import "ASEnvironmentInternal.h" @@ -2721,10 +2721,10 @@ static const char *ASDisplayNodeDrawingPriorityKey = "ASDrawingPriority"; ASEnvironmentLayoutOptionsForwarding ASEnvironmentLayoutExtensibilityForwarding -- (ASDisplayTraits *)displayTraits +- (ASTraitCollection *)asyncTraitCollection { ASDN::MutexLocker l(_propertyLock); - return [ASDisplayTraits displayTraitsWithASEnvironmentDisplayTraits:_environmentState.displayTraits]; + return [ASTraitCollection displayTraitsWithASEnvironmentTraitCollection:_environmentState.traitCollection]; } #if TARGET_OS_TV diff --git a/AsyncDisplayKit/ASTableNode.mm b/AsyncDisplayKit/ASTableNode.mm index 6c9f35f842..7b413bc588 100644 --- a/AsyncDisplayKit/ASTableNode.mm +++ b/AsyncDisplayKit/ASTableNode.mm @@ -163,6 +163,6 @@ [self.view clearFetchedData]; } -ASEnvironmentDisplayTraitsCollectionTableSetEnvironmentState(_environmentStateLock) +ASEnvironmentCollectionTableSetEnvironmentState(_environmentStateLock) @end diff --git a/AsyncDisplayKit/ASViewController.h b/AsyncDisplayKit/ASViewController.h index e1b43342ec..1796cbc459 100644 --- a/AsyncDisplayKit/ASViewController.h +++ b/AsyncDisplayKit/ASViewController.h @@ -9,12 +9,12 @@ #import #import -@class ASDisplayTraits; +@class ASTraitCollection; NS_ASSUME_NONNULL_BEGIN -typedef ASDisplayTraits * _Nonnull (^ASDisplayTraitsForTraitCollectionBlock)(UITraitCollection *traitCollection); -typedef ASDisplayTraits * _Nonnull (^ASDisplayTraitsForTraitWindowSizeBlock)(CGSize windowSize); +typedef ASTraitCollection * _Nonnull (^ASDisplayTraitsForTraitCollectionBlock)(UITraitCollection *traitCollection); +typedef ASTraitCollection * _Nonnull (^ASDisplayTraitsForTraitWindowSizeBlock)(CGSize windowSize); @interface ASViewController<__covariant DisplayNodeType : ASDisplayNode *> : UIViewController diff --git a/AsyncDisplayKit/ASViewController.mm b/AsyncDisplayKit/ASViewController.mm index b4834581de..b902a1ec7e 100644 --- a/AsyncDisplayKit/ASViewController.mm +++ b/AsyncDisplayKit/ASViewController.mm @@ -11,7 +11,7 @@ #import "ASDimension.h" #import "ASDisplayNode+FrameworkPrivate.h" #import "ASDisplayNode+Beta.h" -#import "ASDisplayTraits.h" +#import "ASTraitCollection.h" #import "ASEnvironmentInternal.h" #import "ASRangeControllerUpdateRangeProtocol+Beta.h" @@ -51,7 +51,7 @@ - (void)dealloc { if (_displayTraitsContext != nil) { - ASDisplayTraitsClearDisplayContext(self.node); + ASEnvironmentTraitCollectionClearDisplayContext(self.node); _displayTraitsContext = nil; } } @@ -142,44 +142,44 @@ return _node.interfaceState; } -#pragma mark - ASDisplayTraits +#pragma mark - ASEnvironmentTraitCollection -- (ASEnvironmentDisplayTraits)displayTraitsForTraitCollection:(UITraitCollection *)traitCollection +- (ASEnvironmentTraitCollection)displayTraitsForTraitCollection:(UITraitCollection *)traitCollection { if (self.overrideDisplayTraitsWithTraitCollection) { - ASDisplayTraits *displayTraits = self.overrideDisplayTraitsWithTraitCollection(traitCollection); - displayTraits.isMutable = NO; - return [displayTraits environmentDisplayTraits]; + ASTraitCollection *asyncTraitCollection = self.overrideDisplayTraitsWithTraitCollection(traitCollection); + asyncTraitCollection.isMutable = NO; + return [asyncTraitCollection environmentTraitCollection]; } - ASEnvironmentDisplayTraits displayTraits = ASEnvironmentDisplayTraitsFromUITraitCollection(traitCollection); - displayTraits.displayContext = _displayTraitsContext; - return displayTraits; + ASEnvironmentTraitCollection asyncTraitCollection = ASEnvironmentTraitCollectionFromUITraitCollection(traitCollection); + asyncTraitCollection.displayContext = _displayTraitsContext; + return asyncTraitCollection; } -- (ASEnvironmentDisplayTraits)displayTraitsForWindowSize:(CGSize)windowSize +- (ASEnvironmentTraitCollection)displayTraitsForWindowSize:(CGSize)windowSize { if (self.overrideDisplayTraitsWithWindowSize) { - ASDisplayTraits *displayTraits = self.overrideDisplayTraitsWithWindowSize(windowSize); - displayTraits.isMutable = NO; - return [displayTraits environmentDisplayTraits]; + ASTraitCollection *traitCollection = self.overrideDisplayTraitsWithWindowSize(windowSize); + traitCollection.isMutable = NO; + return [traitCollection environmentTraitCollection]; } - return self.node.environmentState.displayTraits; + return self.node.environmentState.traitCollection; } -- (void)progagateNewDisplayTraits:(ASEnvironmentDisplayTraits)displayTraits +- (void)progagateNewDisplayTraits:(ASEnvironmentTraitCollection)traitCollection { ASEnvironmentState environmentState = self.node.environmentState; - ASEnvironmentDisplayTraits oldDisplayTraits = environmentState.displayTraits; + ASEnvironmentTraitCollection oldTraitCollection = environmentState.traitCollection; - if (ASEnvironmentDisplayTraitsIsEqualToASEnvironmentDisplayTraits(displayTraits, oldDisplayTraits) == NO) { - environmentState.displayTraits = displayTraits; + if (ASEnvironmentTraitCollectionIsEqualToASEnvironmentTraitCollection(traitCollection, oldTraitCollection) == NO) { + environmentState.traitCollection = traitCollection; [self.node setEnvironmentState:environmentState]; [self.node setNeedsLayout]; NSArray> *children = [self.node children]; for (id child in children) { - ASEnvironmentStatePropagateDown(child, environmentState.displayTraits); + ASEnvironmentStatePropagateDown(child, environmentState.traitCollection); } } } @@ -188,24 +188,24 @@ { [super traitCollectionDidChange:previousTraitCollection]; - ASEnvironmentDisplayTraits displayTraits = [self displayTraitsForTraitCollection:self.traitCollection]; - [self progagateNewDisplayTraits:displayTraits]; + ASEnvironmentTraitCollection traitCollection = [self displayTraitsForTraitCollection:self.traitCollection]; + [self progagateNewDisplayTraits:traitCollection]; } - (void)willTransitionToTraitCollection:(UITraitCollection *)newCollection withTransitionCoordinator:(id)coordinator { [super willTransitionToTraitCollection:newCollection withTransitionCoordinator:coordinator]; - ASEnvironmentDisplayTraits displayTraits = [self displayTraitsForTraitCollection:self.traitCollection]; - [self progagateNewDisplayTraits:displayTraits]; + ASEnvironmentTraitCollection traitCollection = [self displayTraitsForTraitCollection:newCollection]; + [self progagateNewDisplayTraits:traitCollection]; } - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator { [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; - ASEnvironmentDisplayTraits displayTraits = [self displayTraitsForWindowSize:size]; - [self progagateNewDisplayTraits:displayTraits]; + ASEnvironmentTraitCollection traitCollection = [self displayTraitsForWindowSize:size]; + [self progagateNewDisplayTraits:traitCollection]; } @end diff --git a/AsyncDisplayKit/Details/ASDataController.mm b/AsyncDisplayKit/Details/ASDataController.mm index 55b43a4d71..ad049cb187 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].displayTraits); + ASEnvironmentStatePropagateDown(cellNode, [environment environmentState].traitCollection); return cellNode; }; diff --git a/AsyncDisplayKit/Details/ASEnvironment.h b/AsyncDisplayKit/Details/ASEnvironment.h index ff24ac0021..99a0a3838b 100644 --- a/AsyncDisplayKit/Details/ASEnvironment.h +++ b/AsyncDisplayKit/Details/ASEnvironment.h @@ -63,7 +63,7 @@ typedef struct ASEnvironmentHierarchyState { #pragma mark - ASEnvironmentDisplayTraits -typedef struct ASEnvironmentDisplayTraits { +typedef struct ASEnvironmentTraitCollection { CGFloat displayScale; UIUserInterfaceSizeClass horizontalSizeClass; UIUserInterfaceIdiom userInterfaceIdiom; @@ -85,25 +85,25 @@ typedef struct ASEnvironmentDisplayTraits { // As an added precaution ASDisplayTraitsClearDisplayContext is called from ASVC's desctructor // which will propagate a nil displayContext to its subnodes. id __unsafe_unretained displayContext; -} ASEnvironmentDisplayTraits; +} ASEnvironmentTraitCollection; -extern void ASDisplayTraitsClearDisplayContext(id rootEnvironment); +extern void ASEnvironmentTraitCollectionClearDisplayContext(id rootEnvironment); -extern ASEnvironmentDisplayTraits ASEnvironmentDisplayTraitsFromUITraitCollection(UITraitCollection *traitCollection); -extern BOOL ASEnvironmentDisplayTraitsIsEqualToASEnvironmentDisplayTraits(ASEnvironmentDisplayTraits displayTraits0, ASEnvironmentDisplayTraits displayTraits1); +extern ASEnvironmentTraitCollection ASEnvironmentTraitCollectionFromUITraitCollection(UITraitCollection *traitCollection); +extern BOOL ASEnvironmentTraitCollectionIsEqualToASEnvironmentTraitCollection(ASEnvironmentTraitCollection displayTraits0, ASEnvironmentTraitCollection displayTraits1); #pragma mark - ASEnvironmentState typedef struct ASEnvironmentState { struct ASEnvironmentHierarchyState hierarchyState; struct ASEnvironmentLayoutOptionsState layoutOptionsState; - struct ASEnvironmentDisplayTraits displayTraits; + struct ASEnvironmentTraitCollection traitCollection; } ASEnvironmentState; extern ASEnvironmentState ASEnvironmentStateMakeDefault(); ASDISPLAYNODE_EXTERN_C_END -@class ASDisplayTraits; +@class ASTraitCollection; #pragma mark - ASEnvironment @@ -131,7 +131,7 @@ ASDISPLAYNODE_EXTERN_C_END - (BOOL)supportsTraitsCollectionPropagation; /// Returns an NSObject-representation of the environment's ASEnvironmentDisplayTraits -- (ASDisplayTraits *)displayTraits; +- (ASTraitCollection *)asyncTraitCollection; @end @@ -142,18 +142,18 @@ ASDISPLAYNODE_EXTERN_C_END // If there is any new downward propagating state, it should be added to this define. // // This logic is used in both ASCollectionNode and ASTableNode -#define ASEnvironmentDisplayTraitsCollectionTableSetEnvironmentState(lock) \ +#define ASEnvironmentCollectionTableSetEnvironmentState(lock) \ - (void)setEnvironmentState:(ASEnvironmentState)environmentState\ {\ ASDN::MutexLocker l(lock);\ - ASEnvironmentDisplayTraits oldDisplayTraits = self.environmentState.displayTraits;\ + ASEnvironmentTraitCollection oldTraits = self.environmentState.traitCollection;\ [super setEnvironmentState:environmentState];\ - ASEnvironmentDisplayTraits currentDisplayTraits = environmentState.displayTraits;\ - if (ASEnvironmentDisplayTraitsIsEqualToASEnvironmentDisplayTraits(currentDisplayTraits, oldDisplayTraits) == NO) {\ + ASEnvironmentTraitCollection currentTraits = environmentState.traitCollection;\ + if (ASEnvironmentTraitCollectionIsEqualToASEnvironmentTraitCollection(currentTraits, oldTraits) == NO) {\ NSArray *> *completedNodes = [self.view.dataController completedNodes];\ for (NSArray *sectionArray in completedNodes) {\ for (ASCellNode *cellNode in sectionArray) {\ - ASEnvironmentStatePropagateDown(cellNode, currentDisplayTraits);\ + ASEnvironmentStatePropagateDown(cellNode, currentTraits);\ [cellNode setNeedsLayout];\ }\ }\ diff --git a/AsyncDisplayKit/Details/ASEnvironment.mm b/AsyncDisplayKit/Details/ASEnvironment.mm index c9c7afc68a..af6ee24f98 100644 --- a/AsyncDisplayKit/Details/ASEnvironment.mm +++ b/AsyncDisplayKit/Details/ASEnvironment.mm @@ -26,12 +26,12 @@ ASEnvironmentHierarchyState _ASEnvironmentHierarchyStateMakeDefault() }; } -extern void ASDisplayTraitsClearDisplayContext(id rootEnvironment) +extern void ASEnvironmentTraitCollectionClearDisplayContext(id rootEnvironment) { ASEnvironmentState envState = [rootEnvironment environmentState]; - ASEnvironmentDisplayTraits displayTraits = envState.displayTraits; + ASEnvironmentTraitCollection displayTraits = envState.traitCollection; displayTraits.displayContext = nil; - envState.displayTraits = displayTraits; + envState.traitCollection = displayTraits; [rootEnvironment setEnvironmentState:envState]; for (id child in [rootEnvironment children]) { @@ -39,37 +39,37 @@ extern void ASDisplayTraitsClearDisplayContext(id rootEnvironment } } -ASEnvironmentDisplayTraits _ASEnvironmentDisplayTraitsMakeDefault() +ASEnvironmentTraitCollection _ASEnvironmentTraitCollectionMakeDefault() { - return (ASEnvironmentDisplayTraits) { + return (ASEnvironmentTraitCollection) { // Default values can be defined in here }; } -ASEnvironmentDisplayTraits ASEnvironmentDisplayTraitsFromUITraitCollection(UITraitCollection *traitCollection) +ASEnvironmentTraitCollection ASEnvironmentTraitCollectionFromUITraitCollection(UITraitCollection *traitCollection) { - ASEnvironmentDisplayTraits displayTraits; + ASEnvironmentTraitCollection asyncTraitCollection; if (AS_AT_LEAST_IOS8) { - displayTraits.displayScale = traitCollection.displayScale; - displayTraits.horizontalSizeClass = traitCollection.horizontalSizeClass; - displayTraits.verticalSizeClass = traitCollection.verticalSizeClass; - displayTraits.userInterfaceIdiom = traitCollection.userInterfaceIdiom; + asyncTraitCollection.displayScale = traitCollection.displayScale; + asyncTraitCollection.horizontalSizeClass = traitCollection.horizontalSizeClass; + asyncTraitCollection.verticalSizeClass = traitCollection.verticalSizeClass; + asyncTraitCollection.userInterfaceIdiom = traitCollection.userInterfaceIdiom; if (AS_AT_LEAST_IOS9) { - displayTraits.forceTouchCapability = traitCollection.forceTouchCapability; + asyncTraitCollection.forceTouchCapability = traitCollection.forceTouchCapability; } } - return displayTraits; + return asyncTraitCollection; } -BOOL ASEnvironmentDisplayTraitsIsEqualToASEnvironmentDisplayTraits(ASEnvironmentDisplayTraits displayTraits0, ASEnvironmentDisplayTraits displayTraits1) +BOOL ASEnvironmentTraitCollectionIsEqualToASEnvironmentTraitCollection(ASEnvironmentTraitCollection traitCollection0, ASEnvironmentTraitCollection traitCollection1) { return - displayTraits0.verticalSizeClass == displayTraits1.verticalSizeClass && - displayTraits0.horizontalSizeClass == displayTraits1.horizontalSizeClass && - displayTraits0.displayScale == displayTraits1.displayScale && - displayTraits0.userInterfaceIdiom == displayTraits1.userInterfaceIdiom && - displayTraits0.forceTouchCapability == displayTraits1.forceTouchCapability && - displayTraits0.displayContext == displayTraits1.displayContext; + traitCollection0.verticalSizeClass == traitCollection1.verticalSizeClass && + traitCollection0.horizontalSizeClass == traitCollection1.horizontalSizeClass && + traitCollection0.displayScale == traitCollection1.displayScale && + traitCollection0.userInterfaceIdiom == traitCollection1.userInterfaceIdiom && + traitCollection0.forceTouchCapability == traitCollection1.forceTouchCapability && + traitCollection0.displayContext == traitCollection1.displayContext; } ASEnvironmentState ASEnvironmentStateMakeDefault() @@ -77,7 +77,7 @@ ASEnvironmentState ASEnvironmentStateMakeDefault() return (ASEnvironmentState) { .layoutOptionsState = _ASEnvironmentLayoutOptionsStateMakeDefault(), .hierarchyState = _ASEnvironmentHierarchyStateMakeDefault(), - .displayTraits = _ASEnvironmentDisplayTraitsMakeDefault() + .traitCollection = _ASEnvironmentTraitCollectionMakeDefault() }; } diff --git a/AsyncDisplayKit/Details/ASDisplayTraits.h b/AsyncDisplayKit/Details/ASTraitCollection.h similarity index 72% rename from AsyncDisplayKit/Details/ASDisplayTraits.h rename to AsyncDisplayKit/Details/ASTraitCollection.h index 983487d2b0..32f65cab89 100644 --- a/AsyncDisplayKit/Details/ASDisplayTraits.h +++ b/AsyncDisplayKit/Details/ASTraitCollection.h @@ -11,7 +11,7 @@ #import #import -@interface ASDisplayTraits : NSObject +@interface ASTraitCollection : NSObject @property (nonatomic, assign) BOOL isMutable; @@ -21,9 +21,9 @@ @property (nonatomic, assign) UIUserInterfaceSizeClass verticalSizeClass; @property (nonatomic, assign) UIForceTouchCapability forceTouchCapability; -+ (ASDisplayTraits *)displayTraitsWithASEnvironmentDisplayTraits:(ASEnvironmentDisplayTraits)traits; -+ (ASDisplayTraits *)displayTraitsWithUITraitCollection:(UITraitCollection *)traitCollection; ++ (ASTraitCollection *)displayTraitsWithASEnvironmentTraitCollection:(ASEnvironmentTraitCollection)traits; ++ (ASTraitCollection *)displayTraitsWithUITraitCollection:(UITraitCollection *)traitCollection; -- (ASEnvironmentDisplayTraits)environmentDisplayTraits; +- (ASEnvironmentTraitCollection)environmentTraitCollection; @end diff --git a/AsyncDisplayKit/Details/ASDisplayTraits.m b/AsyncDisplayKit/Details/ASTraitCollection.m similarity index 56% rename from AsyncDisplayKit/Details/ASDisplayTraits.m rename to AsyncDisplayKit/Details/ASTraitCollection.m index 77478cb672..f13a43a50b 100644 --- a/AsyncDisplayKit/Details/ASDisplayTraits.m +++ b/AsyncDisplayKit/Details/ASTraitCollection.m @@ -6,11 +6,11 @@ // Copyright © 2016 Facebook. All rights reserved. // -#import "ASDisplayTraits.h" +#import "ASTraitCollection.h" #import #import -@implementation ASDisplayTraits +@implementation ASTraitCollection - (instancetype)init { @@ -51,35 +51,35 @@ _forceTouchCapability = forceTouchCapability; } -+ (ASDisplayTraits *)displayTraitsWithASEnvironmentDisplayTraits:(ASEnvironmentDisplayTraits)traits ++ (ASTraitCollection *)displayTraitsWithASEnvironmentTraitCollection:(ASEnvironmentTraitCollection)traits { - ASDisplayTraits *displayTraits = [[ASDisplayTraits alloc] init]; - displayTraits.displayScale = traits.displayScale; - displayTraits.horizontalSizeClass = traits.horizontalSizeClass; - displayTraits.verticalSizeClass = traits.verticalSizeClass; - displayTraits.userInterfaceIdiom = traits.userInterfaceIdiom; - displayTraits.forceTouchCapability = traits.forceTouchCapability; - return displayTraits; + 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; } -+ (ASDisplayTraits *)displayTraitsWithUITraitCollection:(UITraitCollection *)traitCollection ++ (ASTraitCollection *)displayTraitsWithUITraitCollection:(UITraitCollection *)traitCollection { - ASDisplayTraits *displayTraits = [[ASDisplayTraits alloc] init]; + ASTraitCollection *asyncTraitCollection = [[ASTraitCollection alloc] init]; if (AS_AT_LEAST_IOS8) { - displayTraits.displayScale = traitCollection.displayScale; - displayTraits.horizontalSizeClass = traitCollection.horizontalSizeClass; - displayTraits.verticalSizeClass = traitCollection.verticalSizeClass; - displayTraits.userInterfaceIdiom = traitCollection.userInterfaceIdiom; + asyncTraitCollection.displayScale = traitCollection.displayScale; + asyncTraitCollection.horizontalSizeClass = traitCollection.horizontalSizeClass; + asyncTraitCollection.verticalSizeClass = traitCollection.verticalSizeClass; + asyncTraitCollection.userInterfaceIdiom = traitCollection.userInterfaceIdiom; if (AS_AT_LEAST_IOS9) { - displayTraits.forceTouchCapability = traitCollection.forceTouchCapability; + asyncTraitCollection.forceTouchCapability = traitCollection.forceTouchCapability; } } - return displayTraits; + return asyncTraitCollection; } -- (ASEnvironmentDisplayTraits)environmentDisplayTraits +- (ASEnvironmentTraitCollection)environmentTraitCollection { - return (ASEnvironmentDisplayTraits) { + return (ASEnvironmentTraitCollection) { .displayScale = self.displayScale, .horizontalSizeClass = self.horizontalSizeClass, .userInterfaceIdiom = self.userInterfaceIdiom, diff --git a/AsyncDisplayKit/Layout/ASLayoutSpec.mm b/AsyncDisplayKit/Layout/ASLayoutSpec.mm index ef1a32cb2b..0401c1f0f9 100644 --- a/AsyncDisplayKit/Layout/ASLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASLayoutSpec.mm @@ -12,12 +12,12 @@ #import "ASAssert.h" #import "ASBaseDefines.h" -#import "ASDisplayTraits.h" #import "ASEnvironmentInternal.h" #import "ASInternalHelpers.h" #import "ASLayout.h" #import "ASThread.h" +#import "ASTraitCollection.h" #import #import @@ -204,10 +204,10 @@ ASEnvironmentLayoutOptionsForwarding ASEnvironmentLayoutExtensibilityForwarding -- (ASDisplayTraits *)displayTraits +- (ASTraitCollection *)asyncTraitCollection { ASDN::MutexLocker l(_propertyLock); - return [ASDisplayTraits displayTraitsWithASEnvironmentDisplayTraits:_environmentState.displayTraits]; + return [ASTraitCollection displayTraitsWithASEnvironmentTraitCollection:_environmentState.traitCollection]; } @end diff --git a/AsyncDisplayKit/Private/ASEnvironmentInternal.h b/AsyncDisplayKit/Private/ASEnvironmentInternal.h index eeac031a6e..30d62670e7 100644 --- a/AsyncDisplayKit/Private/ASEnvironmentInternal.h +++ b/AsyncDisplayKit/Private/ASEnvironmentInternal.h @@ -49,8 +49,8 @@ ASEnvironmentState ASEnvironmentMergeObjectAndState(ASEnvironmentState environme static const struct ASEnvironmentHierarchyState ASEnvironmentDefaultHierarchyState = {}; ASEnvironmentState ASEnvironmentMergeObjectAndState(ASEnvironmentState environmentState, ASEnvironmentHierarchyState state, ASEnvironmentStatePropagation propagation); -static const struct ASEnvironmentDisplayTraits ASEnvironmentDefaultDisplayTraits = {}; -ASEnvironmentState ASEnvironmentMergeObjectAndState(ASEnvironmentState environmentState, ASEnvironmentDisplayTraits state, ASEnvironmentStatePropagation propagation); +static const struct ASEnvironmentTraitCollection ASEnvironmentDefaultTraitCollection = {}; +ASEnvironmentState ASEnvironmentMergeObjectAndState(ASEnvironmentState environmentState, ASEnvironmentTraitCollection state, ASEnvironmentStatePropagation propagation); #pragma mark - Propagation diff --git a/AsyncDisplayKit/Private/ASEnvironmentInternal.mm b/AsyncDisplayKit/Private/ASEnvironmentInternal.mm index b05df767f5..e74e0abf60 100644 --- a/AsyncDisplayKit/Private/ASEnvironmentInternal.mm +++ b/AsyncDisplayKit/Private/ASEnvironmentInternal.mm @@ -194,21 +194,21 @@ ASEnvironmentState ASEnvironmentMergeObjectAndState(ASEnvironmentState environme return environmentState; } -ASEnvironmentState ASEnvironmentMergeObjectAndState(ASEnvironmentState childEnvironmentState, ASEnvironmentDisplayTraits parentDisplayTraits, ASEnvironmentStatePropagation propagation) { +ASEnvironmentState ASEnvironmentMergeObjectAndState(ASEnvironmentState childEnvironmentState, ASEnvironmentTraitCollection parentTraitCollection, ASEnvironmentStatePropagation propagation) { if (propagation == ASEnvironmentStatePropagation::DOWN && !ASEnvironmentStateTraitCollectionPropagationEnabled()) { return childEnvironmentState; } // Support propagate down if (propagation == ASEnvironmentStatePropagation::DOWN) { - ASEnvironmentDisplayTraits childDisplayTraits = childEnvironmentState.displayTraits; - childDisplayTraits.horizontalSizeClass = parentDisplayTraits.horizontalSizeClass; - childDisplayTraits.verticalSizeClass = parentDisplayTraits.verticalSizeClass; - childDisplayTraits.userInterfaceIdiom = parentDisplayTraits.userInterfaceIdiom; - childDisplayTraits.forceTouchCapability = parentDisplayTraits.forceTouchCapability; - childDisplayTraits.displayScale = parentDisplayTraits.displayScale; - childDisplayTraits.displayContext = parentDisplayTraits.displayContext; - childEnvironmentState.displayTraits = childDisplayTraits; + ASEnvironmentTraitCollection childTraitCollection = childEnvironmentState.traitCollection; + childTraitCollection.horizontalSizeClass = parentTraitCollection.horizontalSizeClass; + childTraitCollection.verticalSizeClass = parentTraitCollection.verticalSizeClass; + childTraitCollection.userInterfaceIdiom = parentTraitCollection.userInterfaceIdiom; + childTraitCollection.forceTouchCapability = parentTraitCollection.forceTouchCapability; + childTraitCollection.displayScale = parentTraitCollection.displayScale; + childTraitCollection.displayContext = parentTraitCollection.displayContext; + childEnvironmentState.traitCollection = childTraitCollection; } return childEnvironmentState; diff --git a/examples/DisplayTraits/Sample.xcworkspace/contents.xcworkspacedata b/examples/ASCollectionView/Sample.xcworkspace/contents.xcworkspacedata similarity index 100% rename from examples/DisplayTraits/Sample.xcworkspace/contents.xcworkspacedata rename to examples/ASCollectionView/Sample.xcworkspace/contents.xcworkspacedata diff --git a/examples/DisplayTraits/Podfile b/examples/ASTraitCollection/Podfile similarity index 100% rename from examples/DisplayTraits/Podfile rename to examples/ASTraitCollection/Podfile diff --git a/examples/DisplayTraits/Sample.xcodeproj/project.pbxproj b/examples/ASTraitCollection/Sample.xcodeproj/project.pbxproj similarity index 100% rename from examples/DisplayTraits/Sample.xcodeproj/project.pbxproj rename to examples/ASTraitCollection/Sample.xcodeproj/project.pbxproj diff --git a/examples/DisplayTraits/Sample.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/examples/ASTraitCollection/Sample.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from examples/DisplayTraits/Sample.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to examples/ASTraitCollection/Sample.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/examples/DisplayTraits/Sample.xcodeproj/xcshareddata/xcschemes/Sample.xcscheme b/examples/ASTraitCollection/Sample.xcodeproj/xcshareddata/xcschemes/Sample.xcscheme similarity index 100% rename from examples/DisplayTraits/Sample.xcodeproj/xcshareddata/xcschemes/Sample.xcscheme rename to examples/ASTraitCollection/Sample.xcodeproj/xcshareddata/xcschemes/Sample.xcscheme diff --git a/examples/ASTraitCollection/Sample.xcworkspace/contents.xcworkspacedata b/examples/ASTraitCollection/Sample.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000..7b5a2f3050 --- /dev/null +++ b/examples/ASTraitCollection/Sample.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/examples/DisplayTraits/Sample/AppDelegate.h b/examples/ASTraitCollection/Sample/AppDelegate.h similarity index 100% rename from examples/DisplayTraits/Sample/AppDelegate.h rename to examples/ASTraitCollection/Sample/AppDelegate.h diff --git a/examples/DisplayTraits/Sample/AppDelegate.m b/examples/ASTraitCollection/Sample/AppDelegate.m similarity index 100% rename from examples/DisplayTraits/Sample/AppDelegate.m rename to examples/ASTraitCollection/Sample/AppDelegate.m diff --git a/examples/DisplayTraits/Sample/CollectionViewController.h b/examples/ASTraitCollection/Sample/CollectionViewController.h similarity index 100% rename from examples/DisplayTraits/Sample/CollectionViewController.h rename to examples/ASTraitCollection/Sample/CollectionViewController.h diff --git a/examples/DisplayTraits/Sample/CollectionViewController.m b/examples/ASTraitCollection/Sample/CollectionViewController.m similarity index 91% rename from examples/DisplayTraits/Sample/CollectionViewController.m rename to examples/ASTraitCollection/Sample/CollectionViewController.m index 018aac6e96..532b43e051 100644 --- a/examples/DisplayTraits/Sample/CollectionViewController.m +++ b/examples/ASTraitCollection/Sample/CollectionViewController.m @@ -11,7 +11,7 @@ #import "CollectionViewController.h" #import "KittenNode.h" -#import +#import @interface CollectionViewController () @property (nonatomic, strong) ASCollectionNode *collectionNode; @@ -62,9 +62,9 @@ - (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath { - ASDisplayTraits *displayTraits = [self.collectionNode displayTraits]; + ASTraitCollection *traitCollection = [self.collectionNode asyncTraitCollection]; - if (displayTraits.horizontalSizeClass == UIUserInterfaceSizeClassRegular) { + if (traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassRegular) { return ASSizeRangeMake(CGSizeMake(200, 120), CGSizeMake(200, 120)); } return ASSizeRangeMake(CGSizeMake(132, 180), CGSizeMake(132, 180)); diff --git a/examples/DisplayTraits/Sample/Info.plist b/examples/ASTraitCollection/Sample/Info.plist similarity index 100% rename from examples/DisplayTraits/Sample/Info.plist rename to examples/ASTraitCollection/Sample/Info.plist diff --git a/examples/DisplayTraits/Sample/KittenNode.h b/examples/ASTraitCollection/Sample/KittenNode.h similarity index 100% rename from examples/DisplayTraits/Sample/KittenNode.h rename to examples/ASTraitCollection/Sample/KittenNode.h diff --git a/examples/DisplayTraits/Sample/KittenNode.m b/examples/ASTraitCollection/Sample/KittenNode.m similarity index 93% rename from examples/DisplayTraits/Sample/KittenNode.m rename to examples/ASTraitCollection/Sample/KittenNode.m index 8139292840..62d7fcdba8 100644 --- a/examples/DisplayTraits/Sample/KittenNode.m +++ b/examples/ASTraitCollection/Sample/KittenNode.m @@ -12,7 +12,7 @@ #import "KittenNode.h" #import "OverrideViewController.h" -#import +#import static const CGFloat kOuterPadding = 16.0f; static const CGFloat kInnerPadding = 10.0f; @@ -130,13 +130,13 @@ static const CGFloat kInnerPadding = 10.0f; - (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize { - ASDisplayTraits *displayTraits = [self displayTraits]; + ASTraitCollection *traitCollection = [self asyncTraitCollection]; ASStackLayoutSpec *stackSpec = [[ASStackLayoutSpec alloc] init]; stackSpec.spacing = kInnerPadding; stackSpec.children = @[_imageNode, _textNode]; - if (displayTraits.horizontalSizeClass == UIUserInterfaceSizeClassRegular) { + if (traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassRegular) { _imageNode.alignSelf = ASStackLayoutAlignSelfStart; stackSpec.direction = ASStackLayoutDirectionHorizontal; } else { @@ -152,10 +152,10 @@ static const CGFloat kInnerPadding = 10.0f; OverrideViewController *overrideVC = [[OverrideViewController alloc] init]; overrideVC.overrideDisplayTraitsWithTraitCollection = ^(UITraitCollection *traitCollection) { - ASDisplayTraits *displayTraits = [ASDisplayTraits displayTraitsWithUITraitCollection:traitCollection]; - displayTraits.horizontalSizeClass = UIUserInterfaceSizeClassCompact; - displayTraits.verticalSizeClass = UIUserInterfaceSizeClassCompact; - return displayTraits; + ASTraitCollection *asyncTraitCollection = [ASTraitCollection displayTraitsWithUITraitCollection:traitCollection]; + asyncTraitCollection.horizontalSizeClass = UIUserInterfaceSizeClassCompact; + asyncTraitCollection.verticalSizeClass = UIUserInterfaceSizeClassCompact; + return asyncTraitCollection; }; [sourceViewController presentViewController:overrideVC animated:YES completion:nil]; diff --git a/examples/DisplayTraits/Sample/Launch Screen.storyboard b/examples/ASTraitCollection/Sample/Launch Screen.storyboard similarity index 100% rename from examples/DisplayTraits/Sample/Launch Screen.storyboard rename to examples/ASTraitCollection/Sample/Launch Screen.storyboard diff --git a/examples/DisplayTraits/Sample/OverrideViewController.h b/examples/ASTraitCollection/Sample/OverrideViewController.h similarity index 100% rename from examples/DisplayTraits/Sample/OverrideViewController.h rename to examples/ASTraitCollection/Sample/OverrideViewController.h diff --git a/examples/DisplayTraits/Sample/OverrideViewController.m b/examples/ASTraitCollection/Sample/OverrideViewController.m similarity index 94% rename from examples/DisplayTraits/Sample/OverrideViewController.m rename to examples/ASTraitCollection/Sample/OverrideViewController.m index 6a99e76a53..7536f1fe90 100644 --- a/examples/DisplayTraits/Sample/OverrideViewController.m +++ b/examples/ASTraitCollection/Sample/OverrideViewController.m @@ -10,7 +10,7 @@ */ #import "OverrideViewController.h" -#import +#import static NSString *kLinkAttributeName = @"PlaceKittenNodeLinkAttributeName"; @@ -44,8 +44,8 @@ static NSString *kLinkAttributeName = @"PlaceKittenNodeLinkAttributeName"; - (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize { CGFloat pointSize = 16.f; - ASDisplayTraits *displayTraits = [self displayTraits]; - if (displayTraits.horizontalSizeClass == UIUserInterfaceSizeClassRegular) { + ASTraitCollection *traitCollection = [self asyncTraitCollection]; + if (traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassRegular) { // This should never happen because we override the VC's display traits to always be compact. pointSize = 100; } diff --git a/examples/DisplayTraits/Sample/TableViewController.h b/examples/ASTraitCollection/Sample/TableViewController.h similarity index 100% rename from examples/DisplayTraits/Sample/TableViewController.h rename to examples/ASTraitCollection/Sample/TableViewController.h diff --git a/examples/DisplayTraits/Sample/TableViewController.m b/examples/ASTraitCollection/Sample/TableViewController.m similarity index 100% rename from examples/DisplayTraits/Sample/TableViewController.m rename to examples/ASTraitCollection/Sample/TableViewController.m diff --git a/examples/DisplayTraits/Sample/ViewController.h b/examples/ASTraitCollection/Sample/ViewController.h similarity index 100% rename from examples/DisplayTraits/Sample/ViewController.h rename to examples/ASTraitCollection/Sample/ViewController.h diff --git a/examples/DisplayTraits/Sample/ViewController.m b/examples/ASTraitCollection/Sample/ViewController.m similarity index 100% rename from examples/DisplayTraits/Sample/ViewController.m rename to examples/ASTraitCollection/Sample/ViewController.m diff --git a/examples/DisplayTraits/Sample/main.m b/examples/ASTraitCollection/Sample/main.m similarity index 100% rename from examples/DisplayTraits/Sample/main.m rename to examples/ASTraitCollection/Sample/main.m From 0806f529a3fec0e300b8e45cc9769bfaadd848ac Mon Sep 17 00:00:00 2001 From: rcancro Date: Thu, 5 May 2016 15:04:57 -0700 Subject: [PATCH 27/52] change ASCOllectionNode back .mm file --- AsyncDisplayKit.xcodeproj/project.pbxproj | 12 ++++++------ .../{ASCollectionNode.m => ASCollectionNode.mm} | 0 2 files changed, 6 insertions(+), 6 deletions(-) rename AsyncDisplayKit/{ASCollectionNode.m => ASCollectionNode.mm} (100%) diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index f55ce2250a..631fc6d0d8 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -111,8 +111,8 @@ 05F20AA41A15733C00DCA68A /* ASImageProtocols.h in Headers */ = {isa = PBXBuildFile; fileRef = 05F20AA31A15733C00DCA68A /* ASImageProtocols.h */; settings = {ATTRIBUTES = (Public, ); }; }; 18C2ED7E1B9B7DE800F627B3 /* ASCollectionNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 18C2ED7C1B9B7DE800F627B3 /* ASCollectionNode.h */; settings = {ATTRIBUTES = (Public, ); }; }; 18C2ED7F1B9B7DE800F627B3 /* ASCollectionNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 18C2ED7C1B9B7DE800F627B3 /* ASCollectionNode.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 18C2ED801B9B7DE800F627B3 /* ASCollectionNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 18C2ED7D1B9B7DE800F627B3 /* ASCollectionNode.m */; }; - 18C2ED831B9B7DE800F627B3 /* ASCollectionNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 18C2ED7D1B9B7DE800F627B3 /* ASCollectionNode.m */; }; + 18C2ED801B9B7DE800F627B3 /* ASCollectionNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = 18C2ED7D1B9B7DE800F627B3 /* ASCollectionNode.mm */; }; + 18C2ED831B9B7DE800F627B3 /* ASCollectionNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = 18C2ED7D1B9B7DE800F627B3 /* ASCollectionNode.mm */; }; 1950C4491A3BB5C1005C8279 /* ASEqualityHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 1950C4481A3BB5C1005C8279 /* ASEqualityHelpers.h */; settings = {ATTRIBUTES = (Public, ); }; }; 204C979E1B362CB3002B1083 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 204C979D1B362CB3002B1083 /* Default-568h@2x.png */; }; 205F0E0F1B371875007741D0 /* UICollectionViewLayout+ASConvenience.h in Headers */ = {isa = PBXBuildFile; fileRef = 205F0E0D1B371875007741D0 /* UICollectionViewLayout+ASConvenience.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -711,7 +711,7 @@ 05EA6FE61AC0966E00E35788 /* ASSnapshotTestCase.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASSnapshotTestCase.mm; sourceTree = ""; }; 05F20AA31A15733C00DCA68A /* ASImageProtocols.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASImageProtocols.h; sourceTree = ""; }; 18C2ED7C1B9B7DE800F627B3 /* ASCollectionNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASCollectionNode.h; sourceTree = ""; }; - 18C2ED7D1B9B7DE800F627B3 /* ASCollectionNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASCollectionNode.m; sourceTree = ""; }; + 18C2ED7D1B9B7DE800F627B3 /* ASCollectionNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASCollectionNode.mm; sourceTree = ""; }; 1950C4481A3BB5C1005C8279 /* ASEqualityHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASEqualityHelpers.h; sourceTree = ""; }; 204C979D1B362CB3002B1083 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Default-568h@2x.png"; path = "../Default-568h@2x.png"; sourceTree = ""; }; 205F0E0D1B371875007741D0 /* UICollectionViewLayout+ASConvenience.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UICollectionViewLayout+ASConvenience.h"; sourceTree = ""; }; @@ -1049,7 +1049,7 @@ 055F1A3A19ABD43F004DAFF1 /* ASCellNode.h */, AC6456071B0A335000CF11B8 /* ASCellNode.mm */, 18C2ED7C1B9B7DE800F627B3 /* ASCollectionNode.h */, - 18C2ED7D1B9B7DE800F627B3 /* ASCollectionNode.m */, + 18C2ED7D1B9B7DE800F627B3 /* ASCollectionNode.mm */, B13CA0FF1C52004900E031AB /* ASCollectionNode+Beta.h */, AC3C4A4F1A1139C100143C57 /* ASCollectionView.h */, AC3C4A501A1139C100143C57 /* ASCollectionView.mm */, @@ -1998,7 +1998,7 @@ AC6456091B0A335000CF11B8 /* ASCellNode.mm in Sources */, DE8BEAC31C2DF3FC00D57C12 /* ASDelegateProxy.m in Sources */, ACF6ED1D1B17843500DA7C62 /* ASCenterLayoutSpec.mm in Sources */, - 18C2ED801B9B7DE800F627B3 /* ASCollectionNode.m in Sources */, + 18C2ED801B9B7DE800F627B3 /* ASCollectionNode.mm in Sources */, 92DD2FE41BF4B97E0074C9DD /* ASMapNode.mm in Sources */, DBC452DC1C5BF64600B16017 /* NSArray+Diffing.m in Sources */, AC3C4A521A1139C100143C57 /* ASCollectionView.mm in Sources */, @@ -2159,7 +2159,7 @@ B35062161B010EFD0018CF92 /* ASBatchContext.mm in Sources */, AC47D9421B3B891B00AAEE9D /* ASCellNode.mm in Sources */, 34EFC7641B701CC600AD841F /* ASCenterLayoutSpec.mm in Sources */, - 18C2ED831B9B7DE800F627B3 /* ASCollectionNode.m in Sources */, + 18C2ED831B9B7DE800F627B3 /* ASCollectionNode.mm in Sources */, E55D86331CA8A14000A0C26F /* ASLayoutable.mm in Sources */, 68B8A4E41CBDB958007E4543 /* ASWeakProxy.m in Sources */, 9C70F20A1CDBE949007D6C76 /* ASTableNode.mm in Sources */, diff --git a/AsyncDisplayKit/ASCollectionNode.m b/AsyncDisplayKit/ASCollectionNode.mm similarity index 100% rename from AsyncDisplayKit/ASCollectionNode.m rename to AsyncDisplayKit/ASCollectionNode.mm From 92ed02fc603f5c65866953d1dac7f75101fa1e6a Mon Sep 17 00:00:00 2001 From: rcancro Date: Fri, 6 May 2016 09:34:31 -0700 Subject: [PATCH 28/52] fix indentation --- examples/BackgroundPropertySetting/Sample/ViewController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/BackgroundPropertySetting/Sample/ViewController.swift b/examples/BackgroundPropertySetting/Sample/ViewController.swift index 88edf7813d..7e3b494ca0 100644 --- a/examples/BackgroundPropertySetting/Sample/ViewController.swift +++ b/examples/BackgroundPropertySetting/Sample/ViewController.swift @@ -24,7 +24,7 @@ final class ViewController: ASViewController, ASCollectionDelegate, ASCollection layout.minimumInteritemSpacing = padding layout.minimumLineSpacing = padding super.init(node: ASCollectionNode(collectionViewLayout: layout)) - navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Color", style: .Plain, target: self, action: #selector(didTapColorsButton)) + navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Color", style: .Plain, target: self, action: #selector(didTapColorsButton)) navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Layout", style: .Plain, target: self, action: #selector(didTapLayoutButton)) collectionNode.delegate = self collectionNode.dataSource = self From 29952713461352b5de5051f746b762887bc9fa4f Mon Sep 17 00:00:00 2001 From: rcancro Date: Fri, 6 May 2016 09:56:54 -0700 Subject: [PATCH 29/52] add ASTraitCollection to umbrella header --- AsyncDisplayKit/AsyncDisplayKit.h | 1 + 1 file changed, 1 insertion(+) diff --git a/AsyncDisplayKit/AsyncDisplayKit.h b/AsyncDisplayKit/AsyncDisplayKit.h index 4035c60416..42a3baa511 100644 --- a/AsyncDisplayKit/AsyncDisplayKit.h +++ b/AsyncDisplayKit/AsyncDisplayKit.h @@ -77,6 +77,7 @@ #import #import #import +#import #import From 905f3a23b01c7b18620f1315b34fd332411e5ad5 Mon Sep 17 00:00:00 2001 From: Levi McCallum Date: Tue, 10 May 2016 15:00:31 -0700 Subject: [PATCH 30/52] Create a new hash table on commit to prevent copy Resolves #1342 --- .../Details/Transactions/_ASAsyncTransactionGroup.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AsyncDisplayKit/Details/Transactions/_ASAsyncTransactionGroup.m b/AsyncDisplayKit/Details/Transactions/_ASAsyncTransactionGroup.m index 5749ab7591..1c8e0fc2dc 100644 --- a/AsyncDisplayKit/Details/Transactions/_ASAsyncTransactionGroup.m +++ b/AsyncDisplayKit/Details/Transactions/_ASAsyncTransactionGroup.m @@ -82,8 +82,8 @@ static void _transactionGroupRunLoopObserverCallback(CFRunLoopObserverRef observ ASDisplayNodeAssertMainThread(); if ([_containerLayers count]) { - NSHashTable *containerLayersToCommit = [_containerLayers copy]; - [_containerLayers removeAllObjects]; + NSHashTable *containerLayersToCommit = _containerLayers; + _containerLayers = [NSHashTable hashTableWithOptions:NSPointerFunctionsObjectPointerPersonality]; for (CALayer *containerLayer in containerLayersToCommit) { // Note that the act of committing a transaction may open a new transaction, From ffde31a1b216d3198e5730fe522701bc2591d4e6 Mon Sep 17 00:00:00 2001 From: rcancro Date: Tue, 10 May 2016 15:25:34 -0700 Subject: [PATCH 31/52] Fixed a crash in ASTextNode that I made fixes a crash introduced by https://github.com/facebook/AsyncDisplayKit/pull/1637 --- AsyncDisplayKit/TextKit/ASTextKitRenderer.mm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/AsyncDisplayKit/TextKit/ASTextKitRenderer.mm b/AsyncDisplayKit/TextKit/ASTextKitRenderer.mm index 4d3c7c3ef9..15f0ecd5fa 100755 --- a/AsyncDisplayKit/TextKit/ASTextKitRenderer.mm +++ b/AsyncDisplayKit/TextKit/ASTextKitRenderer.mm @@ -256,7 +256,9 @@ static NSCharacterSet *_defaultAvoidTruncationCharacterSet() - (std::vector)visibleRanges { - return [self truncater].visibleRanges; + ASTextKitTailTruncater *truncater = [self truncater]; + [truncater truncate]; + return truncater.visibleRanges; } @end From e99bbb0b1e6a73dcf8b2ba75be8c33372c09312b Mon Sep 17 00:00:00 2001 From: Levi McCallum Date: Tue, 10 May 2016 18:06:11 -0700 Subject: [PATCH 32/52] Add Slack to Contributing file --- CONTRIBUTING.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bb92630492..9964214e3b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -25,6 +25,9 @@ Facebook has a [bounty program](https://www.facebook.com/whitehat/) for the safe disclosure of security bugs. In those cases, please go through the process outlined on that page and do not file a public issue. +## Getting Help +We use Slack for real-time debugging, community updates, and general talk about ASDK. Email AsyncDisplayKit(at)gmail.com to get an invite. + ## Coding Style * 2 spaces for indentation rather than tabs From b84ccf00f4728e3c3856fe9e804ab2aa2346fd40 Mon Sep 17 00:00:00 2001 From: Levi McCallum Date: Tue, 10 May 2016 18:06:43 -0700 Subject: [PATCH 33/52] Add Slack to README --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b1e0f3f201..cd2937c04e 100644 --- a/README.md +++ b/README.md @@ -97,13 +97,16 @@ You can also easily [create your own nodes](https://github.com/facebook/AsyncDisplayKit/blob/master/AsyncDisplayKit/ASDisplayNode%2BSubclasses.h) to implement node hierarchies or custom drawing. -### Learn more +## Learn more * Read the [Getting Started guide](http://asyncdisplaykit.org/docs/getting-started.html) * Get the [sample projects](https://github.com/facebook/AsyncDisplayKit/tree/master/examples) * Browse the [API reference](http://asyncdisplaykit.org/appledocs.html) * Watch the [NSLondon talk](http://vimeo.com/103589245) or the [NSSpain talk](https://www.youtube.com/watch?v=RY_X7l1g79Q) +## Getting Help +We use Slack for real-time debugging, community updates, and general talk about ASDK. Email AsyncDisplayKit(at)gmail.com to get an invite. + ## Testing AsyncDisplayKit has extensive unit test coverage. You'll need to run `pod install` in the root AsyncDisplayKit directory to set up OCMock. From 4b54144f556ab9d5692b67759c3d546b2a27a068 Mon Sep 17 00:00:00 2001 From: rcancro Date: Wed, 11 May 2016 10:21:11 -0700 Subject: [PATCH 34/52] 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; }; From 490d51f45a651efe3687e8fbdd6cf99b21f02e6f Mon Sep 17 00:00:00 2001 From: Levi McCallum Date: Wed, 11 May 2016 10:51:29 -0700 Subject: [PATCH 35/52] Add auto inviter --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9964214e3b..c8edc63baf 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -26,7 +26,7 @@ disclosure of security bugs. In those cases, please go through the process outlined on that page and do not file a public issue. ## Getting Help -We use Slack for real-time debugging, community updates, and general talk about ASDK. Email AsyncDisplayKit(at)gmail.com to get an invite. +We use Slack for real-time debugging, community updates, and general talk about ASDK. Signup at http://asdk-slack-auto-invite.herokuapp.com or email AsyncDisplayKit(at)gmail.com to get an invite. ## Coding Style * 2 spaces for indentation rather than tabs From 11446f3bf50e7583c8f97434ebe447cefa670e03 Mon Sep 17 00:00:00 2001 From: Levi McCallum Date: Wed, 11 May 2016 10:52:08 -0700 Subject: [PATCH 36/52] Add auto inviter --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index cd2937c04e..10f28e5005 100644 --- a/README.md +++ b/README.md @@ -105,7 +105,8 @@ to implement node hierarchies or custom drawing. * Watch the [NSLondon talk](http://vimeo.com/103589245) or the [NSSpain talk](https://www.youtube.com/watch?v=RY_X7l1g79Q) ## Getting Help -We use Slack for real-time debugging, community updates, and general talk about ASDK. Email AsyncDisplayKit(at)gmail.com to get an invite. + +We use Slack for real-time debugging, community updates, and general talk about ASDK. Signup at http://asdk-slack-auto-invite.herokuapp.com or email AsyncDisplayKit(at)gmail.com to get an invite. ## Testing From 9b3ecd28a96f1b849d513c90224a47a7758e9952 Mon Sep 17 00:00:00 2001 From: Michael Schneider Date: Wed, 11 May 2016 20:14:22 +0200 Subject: [PATCH 37/52] Fix position of loading spinner in ASVideoNode --- AsyncDisplayKit/ASVideoNode.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AsyncDisplayKit/ASVideoNode.mm b/AsyncDisplayKit/ASVideoNode.mm index 90c41b62aa..e37f0af206 100644 --- a/AsyncDisplayKit/ASVideoNode.mm +++ b/AsyncDisplayKit/ASVideoNode.mm @@ -218,7 +218,7 @@ static NSString * const kStatus = @"status"; if (_spinnerNode) { ASCenterLayoutSpec *centerLayoutSpec = [ASCenterLayoutSpec centerLayoutSpecWithCenteringOptions:ASCenterLayoutSpecCenteringXY sizingOptions:ASCenterLayoutSpecSizingOptionDefault child:_spinnerNode]; centerLayoutSpec.sizeRange = ASRelativeSizeRangeMakeWithExactCGSize(maxSize); - [children addObject:_spinnerNode]; + [children addObject:centerLayoutSpec]; } return [ASStaticLayoutSpec staticLayoutSpecWithChildren:children]; From cfa9dcda5697f1685768110b4bdf68bf7471a88e Mon Sep 17 00:00:00 2001 From: rcancro Date: Wed, 11 May 2016 14:08:06 -0700 Subject: [PATCH 38/52] typo and comment --- AsyncDisplayKit/ASViewController.mm | 8 ++++++-- AsyncDisplayKit/Details/ASTraitCollection.h | 2 +- AsyncDisplayKit/Details/ASTraitCollection.m | 4 ++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/AsyncDisplayKit/ASViewController.mm b/AsyncDisplayKit/ASViewController.mm index f90f34a180..af76607cc9 100644 --- a/AsyncDisplayKit/ASViewController.mm +++ b/AsyncDisplayKit/ASViewController.mm @@ -52,6 +52,10 @@ - (void)dealloc { if (_traitColectionContext != 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.traitColectionContext = nil; } } @@ -158,7 +162,7 @@ { if (self.overrideDisplayTraitsWithTraitCollection) { ASTraitCollection *asyncTraitCollection = self.overrideDisplayTraitsWithTraitCollection(traitCollection); - self.traitColectionContext = asyncTraitCollection.traitColectionContext; + self.traitColectionContext = asyncTraitCollection.traitCollectionContext; return [asyncTraitCollection environmentTraitCollection]; } @@ -171,7 +175,7 @@ { if (self.overrideDisplayTraitsWithWindowSize) { ASTraitCollection *traitCollection = self.overrideDisplayTraitsWithWindowSize(windowSize); - self.traitColectionContext = traitCollection.traitColectionContext; + self.traitColectionContext = traitCollection.traitCollectionContext; return [traitCollection environmentTraitCollection]; } return self.node.environmentTraitCollection; diff --git a/AsyncDisplayKit/Details/ASTraitCollection.h b/AsyncDisplayKit/Details/ASTraitCollection.h index 0367e2fcd9..2168a40302 100644 --- a/AsyncDisplayKit/Details/ASTraitCollection.h +++ b/AsyncDisplayKit/Details/ASTraitCollection.h @@ -32,7 +32,7 @@ * 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; +@property (nonatomic, strong, readonly) id traitCollectionContext; + (ASTraitCollection *)traitCollectionWithASEnvironmentTraitCollection:(ASEnvironmentTraitCollection)traits; diff --git a/AsyncDisplayKit/Details/ASTraitCollection.m b/AsyncDisplayKit/Details/ASTraitCollection.m index 9e41d2b273..af492c759f 100644 --- a/AsyncDisplayKit/Details/ASTraitCollection.m +++ b/AsyncDisplayKit/Details/ASTraitCollection.m @@ -26,7 +26,7 @@ _horizontalSizeClass = horizontalSizeClass; _verticalSizeClass = verticalSizeClass; _forceTouchCapability = forceTouchCapability; - _traitColectionContext = traitCollectionContext; + _traitCollectionContext = traitCollectionContext; } return self; } @@ -91,7 +91,7 @@ .userInterfaceIdiom = self.userInterfaceIdiom, .verticalSizeClass = self.verticalSizeClass, .forceTouchCapability = self.forceTouchCapability, - .displayContext = self.traitColectionContext, + .displayContext = self.traitCollectionContext, }; } From 8e444092beeefb9aa25d33bdc6818714a3866b04 Mon Sep 17 00:00:00 2001 From: rcancro Date: Thu, 12 May 2016 13:13:30 -0700 Subject: [PATCH 39/52] [ASEnvironment] Remove unneeded locking on environmentState --- AsyncDisplayKit/ASDisplayNode.mm | 2 -- AsyncDisplayKit/Layout/ASLayoutSpec.mm | 2 -- 2 files changed, 4 deletions(-) diff --git a/AsyncDisplayKit/ASDisplayNode.mm b/AsyncDisplayKit/ASDisplayNode.mm index ead40263d4..78ebea1768 100644 --- a/AsyncDisplayKit/ASDisplayNode.mm +++ b/AsyncDisplayKit/ASDisplayNode.mm @@ -2688,13 +2688,11 @@ static const char *ASDisplayNodeDrawingPriorityKey = "ASDrawingPriority"; - (ASEnvironmentState)environmentState { - ASDN::MutexLocker l(_propertyLock); return _environmentState; } - (void)setEnvironmentState:(ASEnvironmentState)environmentState { - ASDN::MutexLocker l(_propertyLock); _environmentState = environmentState; } diff --git a/AsyncDisplayKit/Layout/ASLayoutSpec.mm b/AsyncDisplayKit/Layout/ASLayoutSpec.mm index 7d8995978b..8932e27555 100644 --- a/AsyncDisplayKit/Layout/ASLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASLayoutSpec.mm @@ -169,13 +169,11 @@ - (ASEnvironmentState)environmentState { - ASDN::MutexLocker l(_propertyLock); return _environmentState; } - (void)setEnvironmentState:(ASEnvironmentState)environmentState { - ASDN::MutexLocker l(_propertyLock); _environmentState = environmentState; } From b34e8d78de20ea11b2b07a24df3b12d2936d1a5e Mon Sep 17 00:00:00 2001 From: Garrett Moon Date: Thu, 12 May 2016 13:16:39 -0700 Subject: [PATCH 40/52] ASViewController.m -> ASViewController.mm upstream --- AsyncDisplayKit/ASViewController.mm | 92 +---------------------------- 1 file changed, 1 insertion(+), 91 deletions(-) diff --git a/AsyncDisplayKit/ASViewController.mm b/AsyncDisplayKit/ASViewController.mm index af76607cc9..db5b1e5b4d 100644 --- a/AsyncDisplayKit/ASViewController.mm +++ b/AsyncDisplayKit/ASViewController.mm @@ -9,11 +9,8 @@ #import "ASViewController.h" #import "ASAssert.h" #import "ASDimension.h" -#import "ASDisplayNodeInternal.h" #import "ASDisplayNode+FrameworkPrivate.h" #import "ASDisplayNode+Beta.h" -#import "ASTraitCollection.h" -#import "ASEnvironmentInternal.h" #import "ASRangeControllerUpdateRangeProtocol+Beta.h" @implementation ASViewController @@ -45,21 +42,10 @@ _node = node; _automaticallyAdjustRangeModeBasedOnViewEvents = NO; - + return self; } -- (void)dealloc -{ - if (_traitColectionContext != 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.traitColectionContext = nil; - } -} - - (void)loadView { ASDisplayNodeAssertTrue(!_node.layerBacked); @@ -146,80 +132,4 @@ return _node.interfaceState; } -#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); - self.traitColectionContext = asyncTraitCollection.traitCollectionContext; - return [asyncTraitCollection environmentTraitCollection]; - } - - ASEnvironmentTraitCollection asyncTraitCollection = ASEnvironmentTraitCollectionFromUITraitCollection(traitCollection); - asyncTraitCollection.displayContext = self.traitColectionContext; - return asyncTraitCollection; -} - -- (ASEnvironmentTraitCollection)displayTraitsForWindowSize:(CGSize)windowSize -{ - if (self.overrideDisplayTraitsWithWindowSize) { - ASTraitCollection *traitCollection = self.overrideDisplayTraitsWithWindowSize(windowSize); - self.traitColectionContext = traitCollection.traitCollectionContext; - return [traitCollection environmentTraitCollection]; - } - return self.node.environmentTraitCollection; -} - -- (void)progagateNewDisplayTraits:(ASEnvironmentTraitCollection)traitCollection -{ - ASEnvironmentState environmentState = self.node.environmentState; - ASEnvironmentTraitCollection oldTraitCollection = environmentState.traitCollection; - - if (ASEnvironmentTraitCollectionIsEqualToASEnvironmentTraitCollection(traitCollection, oldTraitCollection) == NO) { - environmentState.traitCollection = traitCollection; - self.node.environmentState = environmentState; - [self.node setNeedsLayout]; - - NSArray> *children = [self.node children]; - for (id child in children) { - ASEnvironmentStatePropagateDown(child, environmentState.traitCollection); - } - } -} - -- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection -{ - [super traitCollectionDidChange:previousTraitCollection]; - - ASEnvironmentTraitCollection traitCollection = [self displayTraitsForTraitCollection:self.traitCollection]; - [self progagateNewDisplayTraits:traitCollection]; -} - -- (void)willTransitionToTraitCollection:(UITraitCollection *)newCollection withTransitionCoordinator:(id)coordinator -{ - [super willTransitionToTraitCollection:newCollection withTransitionCoordinator:coordinator]; - - ASEnvironmentTraitCollection traitCollection = [self displayTraitsForTraitCollection:newCollection]; - [self progagateNewDisplayTraits:traitCollection]; -} - -- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator -{ - [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; - - ASEnvironmentTraitCollection traitCollection = [self displayTraitsForWindowSize:size]; - [self progagateNewDisplayTraits:traitCollection]; -} - @end From af7a2f09d782a0c8acbc5339409407227d99e436 Mon Sep 17 00:00:00 2001 From: Garrett Moon Date: Mon, 9 May 2016 13:48:22 -0700 Subject: [PATCH 41/52] Add support for visibility depth This adds support for the concept of visibility depth. Visibility essentially defines the number of user actions it would take a user to have a view controller visible. Knowing a view controllers visibility depth allows view controllers to take action such as clearing out memory that can be restored at a later date. This patch also add two new view controller subclasses which adopt the ASManagesChildVisibilityDepth protocol. Any view controller that has child view controllers can adopt this protocol to indicate to the child what they're visibility is. For example, ASNavigationController will return a visibility depth of it's own visibilityDepth + 1 for a view controller that would be revealed by tapping the back button. --- AsyncDisplayKit.xcodeproj/project.pbxproj | 34 ++++++ AsyncDisplayKit/ASNavigationController.h | 15 +++ AsyncDisplayKit/ASNavigationController.m | 121 ++++++++++++++++++++++ AsyncDisplayKit/ASTabBarController.h | 15 +++ AsyncDisplayKit/ASTabBarController.m | 98 ++++++++++++++++++ AsyncDisplayKit/ASViewController.h | 3 +- AsyncDisplayKit/ASViewController.mm | 68 +++++++++++- AsyncDisplayKit/ASVisibilityProtocols.h | 45 ++++++++ AsyncDisplayKit/ASVisibilityProtocols.m | 23 ++++ AsyncDisplayKit/AsyncDisplayKit.h | 3 + 10 files changed, 420 insertions(+), 5 deletions(-) create mode 100644 AsyncDisplayKit/ASNavigationController.h create mode 100644 AsyncDisplayKit/ASNavigationController.m create mode 100644 AsyncDisplayKit/ASTabBarController.h create mode 100644 AsyncDisplayKit/ASTabBarController.m create mode 100644 AsyncDisplayKit/ASVisibilityProtocols.h create mode 100644 AsyncDisplayKit/ASVisibilityProtocols.m diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index 631fc6d0d8..722bae0679 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -272,6 +272,17 @@ 68EE0DBE1C1B4ED300BA1B99 /* ASMainSerialQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 68EE0DBB1C1B4ED300BA1B99 /* ASMainSerialQueue.h */; }; 68EE0DBF1C1B4ED300BA1B99 /* ASMainSerialQueue.mm in Sources */ = {isa = PBXBuildFile; fileRef = 68EE0DBC1C1B4ED300BA1B99 /* ASMainSerialQueue.mm */; }; 68EE0DC01C1B4ED300BA1B99 /* ASMainSerialQueue.mm in Sources */ = {isa = PBXBuildFile; fileRef = 68EE0DBC1C1B4ED300BA1B99 /* ASMainSerialQueue.mm */; }; + 68FC85DE1CE29AB700EDD713 /* ASNavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = 68FC85DC1CE29AB700EDD713 /* ASNavigationController.h */; }; + 68FC85DF1CE29AB700EDD713 /* ASNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 68FC85DD1CE29AB700EDD713 /* ASNavigationController.m */; }; + 68FC85E21CE29B7E00EDD713 /* ASTabBarController.h in Headers */ = {isa = PBXBuildFile; fileRef = 68FC85E01CE29B7E00EDD713 /* ASTabBarController.h */; }; + 68FC85E31CE29B7E00EDD713 /* ASTabBarController.h in Headers */ = {isa = PBXBuildFile; fileRef = 68FC85E01CE29B7E00EDD713 /* ASTabBarController.h */; }; + 68FC85E41CE29B7E00EDD713 /* ASTabBarController.m in Sources */ = {isa = PBXBuildFile; fileRef = 68FC85E11CE29B7E00EDD713 /* ASTabBarController.m */; }; + 68FC85E51CE29B7E00EDD713 /* ASTabBarController.m in Sources */ = {isa = PBXBuildFile; fileRef = 68FC85E11CE29B7E00EDD713 /* ASTabBarController.m */; }; + 68FC85E61CE29B9400EDD713 /* ASNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 68FC85DD1CE29AB700EDD713 /* ASNavigationController.m */; }; + 68FC85E91CE29C7D00EDD713 /* ASVisibilityProtocols.h in Headers */ = {isa = PBXBuildFile; fileRef = 68FC85E71CE29C7D00EDD713 /* ASVisibilityProtocols.h */; }; + 68FC85EA1CE29C7D00EDD713 /* ASVisibilityProtocols.h in Headers */ = {isa = PBXBuildFile; fileRef = 68FC85E71CE29C7D00EDD713 /* ASVisibilityProtocols.h */; }; + 68FC85EB1CE29C7D00EDD713 /* ASVisibilityProtocols.m in Sources */ = {isa = PBXBuildFile; fileRef = 68FC85E81CE29C7D00EDD713 /* ASVisibilityProtocols.m */; }; + 68FC85EC1CE29C7D00EDD713 /* ASVisibilityProtocols.m in Sources */ = {isa = PBXBuildFile; fileRef = 68FC85E81CE29C7D00EDD713 /* ASVisibilityProtocols.m */; }; 698548631CA9E025008A345F /* ASEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = 698548611CA9E025008A345F /* ASEnvironment.h */; settings = {ATTRIBUTES = (Public, ); }; }; 698548641CA9E025008A345F /* ASEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = 698548611CA9E025008A345F /* ASEnvironment.h */; settings = {ATTRIBUTES = (Public, ); }; }; 698C8B611CAB49FC0052DC3F /* ASLayoutableExtensibility.h in Headers */ = {isa = PBXBuildFile; fileRef = 698C8B601CAB49FC0052DC3F /* ASLayoutableExtensibility.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -787,6 +798,12 @@ 68B8A4E01CBDB958007E4543 /* ASWeakProxy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASWeakProxy.m; sourceTree = ""; }; 68EE0DBB1C1B4ED300BA1B99 /* ASMainSerialQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASMainSerialQueue.h; sourceTree = ""; }; 68EE0DBC1C1B4ED300BA1B99 /* ASMainSerialQueue.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASMainSerialQueue.mm; sourceTree = ""; }; + 68FC85DC1CE29AB700EDD713 /* ASNavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASNavigationController.h; sourceTree = ""; }; + 68FC85DD1CE29AB700EDD713 /* ASNavigationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASNavigationController.m; sourceTree = ""; }; + 68FC85E01CE29B7E00EDD713 /* ASTabBarController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASTabBarController.h; sourceTree = ""; }; + 68FC85E11CE29B7E00EDD713 /* ASTabBarController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASTabBarController.m; sourceTree = ""; }; + 68FC85E71CE29C7D00EDD713 /* ASVisibilityProtocols.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASVisibilityProtocols.h; sourceTree = ""; }; + 68FC85E81CE29C7D00EDD713 /* ASVisibilityProtocols.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASVisibilityProtocols.m; sourceTree = ""; }; 698548611CA9E025008A345F /* ASEnvironment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASEnvironment.h; sourceTree = ""; }; 698C8B601CAB49FC0052DC3F /* ASLayoutableExtensibility.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASLayoutableExtensibility.h; path = AsyncDisplayKit/Layout/ASLayoutableExtensibility.h; sourceTree = ""; }; 69CB62A91CB8165900024920 /* _ASDisplayViewAccessiblity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _ASDisplayViewAccessiblity.h; sourceTree = ""; }; @@ -1075,6 +1092,8 @@ 68355B2E1CB5799E001D4E68 /* ASImageNode+AnimatedImage.mm */, 0516FA3E1A1563D200B4EBED /* ASMultiplexImageNode.h */, 0516FA3F1A1563D200B4EBED /* ASMultiplexImageNode.mm */, + 68FC85DC1CE29AB700EDD713 /* ASNavigationController.h */, + 68FC85DD1CE29AB700EDD713 /* ASNavigationController.m */, 055B9FA61A1C154B00035D6D /* ASNetworkImageNode.h */, 055B9FA71A1C154B00035D6D /* ASNetworkImageNode.mm */, 25E327541C16819500A2170C /* ASPagerNode.h */, @@ -1083,6 +1102,8 @@ A2763D781CBDD57D00A9ADBD /* ASPINRemoteImageDownloader.m */, D785F6601A74327E00291744 /* ASScrollNode.h */, D785F6611A74327E00291744 /* ASScrollNode.m */, + 68FC85E01CE29B7E00EDD713 /* ASTabBarController.h */, + 68FC85E11CE29B7E00EDD713 /* ASTabBarController.m */, B0F880581BEAEC7500D17647 /* ASTableNode.h */, 9CFFC6C11CCAC768006A6476 /* ASTableNode.mm */, 055F1A3219ABD3E3004DAFF1 /* ASTableView.h */, @@ -1098,6 +1119,8 @@ 764D83D21C8EA515009B4FB8 /* AsyncDisplayKit+Debug.h */, 764D83D31C8EA515009B4FB8 /* AsyncDisplayKit+Debug.m */, DB55C2651C641AE4004EDCF5 /* ASContextTransitioning.h */, + 68FC85E71CE29C7D00EDD713 /* ASVisibilityProtocols.h */, + 68FC85E81CE29C7D00EDD713 /* ASVisibilityProtocols.m */, 92074A5E1CC8B9DD00918F75 /* tvOS */, 058D09E1195D050800B7D73C /* Details */, 058D0A01195D050800B7D73C /* Private */, @@ -1493,6 +1516,7 @@ 058D0A82195D060300B7D73C /* ASAssert.h in Headers */, 0516FA3C1A15563400B4EBED /* ASAvailability.h in Headers */, AEB7B01A1C5962EA00662EF4 /* ASDefaultPlayButton.h in Headers */, + 68FC85E21CE29B7E00EDD713 /* ASTabBarController.h in Headers */, ACF6ED1A1B17843500DA7C62 /* ASBackgroundLayoutSpec.h in Headers */, 058D0A83195D060300B7D73C /* ASBaseDefines.h in Headers */, 054963491A1EA066000F8E56 /* ASBasicImageDownloader.h in Headers */, @@ -1508,6 +1532,7 @@ AC3C4A511A1139C100143C57 /* ASCollectionView.h in Headers */, AEEC47E11C20C2DD00EC1693 /* ASVideoNode.h in Headers */, DE8BEAC11C2DF3FC00D57C12 /* ASDelegateProxy.h in Headers */, + 68FC85DE1CE29AB700EDD713 /* ASNavigationController.h in Headers */, 205F0E1D1B373A2C007741D0 /* ASCollectionViewLayoutController.h in Headers */, AC3C4A541A113EEC00143C57 /* ASCollectionViewProtocols.h in Headers */, 058D0A49195D05CB00B7D73C /* ASControlNode+Subclasses.h in Headers */, @@ -1533,6 +1558,7 @@ 0587F9BD1A7309ED00AFF0BA /* ASEditableTextNode.h in Headers */, DE6EA3221C14000600183B10 /* ASDisplayNode+FrameworkPrivate.h in Headers */, 1950C4491A3BB5C1005C8279 /* ASEqualityHelpers.h in Headers */, + 68FC85E91CE29C7D00EDD713 /* ASVisibilityProtocols.h in Headers */, 257754A81BEE44CD00737CA5 /* ASTextKitContext.h in Headers */, DB55C2611C6408D6004EDCF5 /* _ASTransitionContext.h in Headers */, 464052221A3F83C40061C0BA /* ASFlowLayoutController.h in Headers */, @@ -1667,6 +1693,7 @@ CC3B20841C3F76D600798563 /* ASPendingStateController.h in Headers */, 92074A621CC8BA1900918F75 /* ASImageNode+tvOS.h in Headers */, B35061F71B010EFD0018CF92 /* ASCollectionViewProtocols.h in Headers */, + 68FC85E31CE29B7E00EDD713 /* ASTabBarController.h in Headers */, DE6EA3231C14000600183B10 /* ASDisplayNode+FrameworkPrivate.h in Headers */, 9C70F20F1CDBE9FF007D6C76 /* ASLayoutManager.h in Headers */, B35061FA1B010EFD0018CF92 /* ASControlNode+Subclasses.h in Headers */, @@ -1674,6 +1701,7 @@ B35062171B010EFD0018CF92 /* ASDataController.h in Headers */, B35062191B010EFD0018CF92 /* ASDealloc2MainObject.h in Headers */, 34EFC75B1B701BAF00AD841F /* ASDimension.h in Headers */, + 68FC85EA1CE29C7D00EDD713 /* ASVisibilityProtocols.h in Headers */, A37320101C571B740011FC94 /* ASTextNode+Beta.h in Headers */, DBABFAFC1C6A8D2F0039EA4A /* _ASTransitionContext.h in Headers */, 9C70F2061CDA4F0C007D6C76 /* ASTraitCollection.h in Headers */, @@ -1975,6 +2003,7 @@ files = ( 058D0A22195D050800B7D73C /* _ASAsyncTransaction.mm in Sources */, E55D86321CA8A14000A0C26F /* ASLayoutable.mm in Sources */, + 68FC85E41CE29B7E00EDD713 /* ASTabBarController.m in Sources */, 058D0A23195D050800B7D73C /* _ASAsyncTransactionContainer.m in Sources */, 058D0A24195D050800B7D73C /* _ASAsyncTransactionGroup.m in Sources */, 68355B3A1CB57A5A001D4E68 /* ASPINRemoteImageDownloader.m in Sources */, @@ -2004,6 +2033,7 @@ AC3C4A521A1139C100143C57 /* ASCollectionView.mm in Sources */, 9CFFC6C21CCAC768006A6476 /* ASTableNode.mm in Sources */, 205F0E1E1B373A2C007741D0 /* ASCollectionViewLayoutController.mm in Sources */, + 68FC85EB1CE29C7D00EDD713 /* ASVisibilityProtocols.m in Sources */, 058D0A13195D050800B7D73C /* ASControlNode.mm in Sources */, 464052211A3F83C40061C0BA /* ASDataController.mm in Sources */, B30BF6531C5964B0004FCD53 /* ASLayoutManager.m in Sources */, @@ -2028,6 +2058,7 @@ 430E7C911B4C23F100697A4C /* ASIndexPath.m in Sources */, ACF6ED231B17843500DA7C62 /* ASInsetLayoutSpec.mm in Sources */, ACF6ED4C1B17847A00DA7C62 /* ASInternalHelpers.mm in Sources */, + 68FC85DF1CE29AB700EDD713 /* ASNavigationController.m in Sources */, ACF6ED251B17843500DA7C62 /* ASLayout.mm in Sources */, DB55C2631C6408D6004EDCF5 /* _ASTransitionContext.m in Sources */, 92074A631CC8BA1900918F75 /* ASImageNode+tvOS.m in Sources */, @@ -2161,6 +2192,7 @@ 34EFC7641B701CC600AD841F /* ASCenterLayoutSpec.mm in Sources */, 18C2ED831B9B7DE800F627B3 /* ASCollectionNode.mm in Sources */, E55D86331CA8A14000A0C26F /* ASLayoutable.mm in Sources */, + 68FC85EC1CE29C7D00EDD713 /* ASVisibilityProtocols.m in Sources */, 68B8A4E41CBDB958007E4543 /* ASWeakProxy.m in Sources */, 9C70F20A1CDBE949007D6C76 /* ASTableNode.mm in Sources */, 69CB62AE1CB8165900024920 /* _ASDisplayViewAccessiblity.mm in Sources */, @@ -2209,6 +2241,7 @@ 044285101BAA64EC00D16268 /* ASMultidimensionalArrayUtils.mm in Sources */, B35062271B010EFD0018CF92 /* ASRangeController.mm in Sources */, 0442850A1BAA63FE00D16268 /* ASBatchFetching.m in Sources */, + 68FC85E61CE29B9400EDD713 /* ASNavigationController.m in Sources */, 34EFC76F1B701CF700AD841F /* ASRatioLayoutSpec.mm in Sources */, 254C6B8B1BF94F8A003EC431 /* ASTextKitShadower.mm in Sources */, 34EFC7661B701CD200AD841F /* ASRelativeSize.mm in Sources */, @@ -2223,6 +2256,7 @@ 9C70F2051CDA4F06007D6C76 /* ASTraitCollection.m in Sources */, 34EFC7781B701D3100AD841F /* ASStackUnpositionedLayout.mm in Sources */, DE84918E1C8FFF9F003D89E9 /* ASRunLoopQueue.mm in Sources */, + 68FC85E51CE29B7E00EDD713 /* ASTabBarController.m in Sources */, AC026B6C1BD57D6F00BBC17E /* ASChangeSetDataController.m in Sources */, 34EFC7741B701D0A00AD841F /* ASStaticLayoutSpec.mm in Sources */, 92074A6A1CC8BADA00918F75 /* ASControlNode+tvOS.m in Sources */, diff --git a/AsyncDisplayKit/ASNavigationController.h b/AsyncDisplayKit/ASNavigationController.h new file mode 100644 index 0000000000..c849f708a0 --- /dev/null +++ b/AsyncDisplayKit/ASNavigationController.h @@ -0,0 +1,15 @@ +// +// ASNavigationController.h +// Pods +// +// Created by Garrett Moon on 4/27/16. +// +// + +#import + +#import "ASVisibilityProtocols.h" + +@interface ASNavigationController : UINavigationController + +@end diff --git a/AsyncDisplayKit/ASNavigationController.m b/AsyncDisplayKit/ASNavigationController.m new file mode 100644 index 0000000000..7f5af99d6e --- /dev/null +++ b/AsyncDisplayKit/ASNavigationController.m @@ -0,0 +1,121 @@ +// +// ASNavigationController.m +// Pods +// +// Created by Garrett Moon on 4/27/16. +// +// + +#import "ASNavigationController.h" + +@implementation ASNavigationController +{ + BOOL _parentManagesVisibilityDepth; + NSInteger _visibilityDepth; +} + +- (void)didMoveToParentViewController:(UIViewController *)parent +{ + [super didMoveToParentViewController:parent]; + [self visibilityDepthDidChange]; +} + +- (void)viewWillAppear:(BOOL)animated +{ + [super viewWillAppear:animated]; + + if (_parentManagesVisibilityDepth == NO) { + _visibilityDepth = 0; + [self visibilityDepthDidChange]; + } +} + +- (void)viewDidDisappear:(BOOL)animated +{ + [super viewDidDisappear:animated]; + + if (_parentManagesVisibilityDepth == NO) { + _visibilityDepth = 1; + [self visibilityDepthDidChange]; + } +} + +- (NSInteger)visibilityDepth +{ + if (self.parentViewController && _parentManagesVisibilityDepth == NO) { + _parentManagesVisibilityDepth = [self.parentViewController conformsToProtocol:@protocol(ASManagesChildVisibilityDepth)]; + } + + if (_parentManagesVisibilityDepth) { + return [(id )self.parentViewController visibilityDepthOfChildViewController:self]; + } + return _visibilityDepth; +} + +- (void)visibilityDepthDidChange +{ + for (UIViewController *viewController in self.viewControllers) { + if ([viewController conformsToProtocol:@protocol(ASVisibilityDepth)]) { + [(id )viewController visibilityDepthDidChange]; + } + } +} + +- (NSInteger)visibilityDepthOfChildViewController:(UIViewController *)childViewController +{ + NSUInteger viewControllerIndex = [self.viewControllers indexOfObject:childViewController]; + NSAssert(viewControllerIndex != NSNotFound, @"childViewController is not in the navigation stack."); + + if (viewControllerIndex == self.viewControllers.count - 1) { + //view controller is at the top + return [self visibilityDepth] + 0; + } else if (viewControllerIndex == 0) { + //view controller is the root view controller. Can be accessed by holding the back button. + return [self visibilityDepth] + 1; + } + + return [self visibilityDepth] + self.viewControllers.count - 1 - viewControllerIndex; +} + +#pragma mark - UIKit overrides + +- (NSArray *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated +{ + NSArray *viewControllers = [super popToViewController:viewController animated:animated]; + [self visibilityDepthDidChange]; + return viewControllers; +} + +- (NSArray *)popToRootViewControllerAnimated:(BOOL)animated +{ + NSArray *viewControllers = [super popToRootViewControllerAnimated:animated]; + [self visibilityDepthDidChange]; + return viewControllers; +} + +- (void)setViewControllers:(NSArray *)viewControllers +{ + [super setViewControllers:viewControllers]; + [self visibilityDepthDidChange]; +} + +- (void)setViewControllers:(NSArray *)viewControllers animated:(BOOL)animated +{ + [super setViewControllers:viewControllers animated:animated]; + [self visibilityDepthDidChange]; +} + +- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated +{ + [super pushViewController:viewController animated:animated]; + [self visibilityDepthDidChange]; +} + +- (UIViewController *)popViewControllerAnimated:(BOOL)animated +{ + UIViewController *viewController = [super popViewControllerAnimated:animated]; + [self visibilityDepthDidChange]; + return viewController; +} + +@end diff --git a/AsyncDisplayKit/ASTabBarController.h b/AsyncDisplayKit/ASTabBarController.h new file mode 100644 index 0000000000..6c633a8a26 --- /dev/null +++ b/AsyncDisplayKit/ASTabBarController.h @@ -0,0 +1,15 @@ +// +// ASTabBarController.h +// AsyncDisplayKit +// +// Created by Garrett Moon on 5/10/16. +// Copyright © 2016 Facebook. All rights reserved. +// + +#import + +#import "ASVisibilityProtocols.h" + +@interface ASTabBarController : UITabBarController + +@end diff --git a/AsyncDisplayKit/ASTabBarController.m b/AsyncDisplayKit/ASTabBarController.m new file mode 100644 index 0000000000..b083dba7a9 --- /dev/null +++ b/AsyncDisplayKit/ASTabBarController.m @@ -0,0 +1,98 @@ +// +// ASTabBarController.m +// AsyncDisplayKit +// +// Created by Garrett Moon on 5/10/16. +// Copyright © 2016 Facebook. All rights reserved. +// + +#import "ASTabBarController.h" + +@implementation ASTabBarController +{ + BOOL _parentManagesVisibilityDepth; + NSInteger _visibilityDepth; +} + +- (void)didMoveToParentViewController:(UIViewController *)parent +{ + [super didMoveToParentViewController:parent]; + [self visibilityDepthDidChange]; +} + +- (void)viewWillAppear:(BOOL)animated +{ + [super viewWillAppear:animated]; + + if (_parentManagesVisibilityDepth == NO) { + _visibilityDepth = 0; + [self visibilityDepthDidChange]; + } +} + +- (void)viewDidDisappear:(BOOL)animated +{ + [super viewDidDisappear:animated]; + + if (_parentManagesVisibilityDepth == NO) { + _visibilityDepth = 1; + [self visibilityDepthDidChange]; + } +} + +- (NSInteger)visibilityDepth +{ + if (self.parentViewController && _parentManagesVisibilityDepth == NO) { + _parentManagesVisibilityDepth = [self.parentViewController conformsToProtocol:@protocol(ASManagesChildVisibilityDepth)]; + } + + if (_parentManagesVisibilityDepth) { + return [(id )self.parentViewController visibilityDepthOfChildViewController:self]; + } + return _visibilityDepth; +} + +- (void)visibilityDepthDidChange +{ + for (UIViewController *viewController in self.viewControllers) { + if ([viewController conformsToProtocol:@protocol(ASVisibilityDepth)]) { + [(id )viewController visibilityDepthDidChange]; + } + } +} + +- (NSInteger)visibilityDepthOfChildViewController:(UIViewController *)childViewController +{ + if (self.selectedViewController == childViewController) { + return [self visibilityDepth]; + } + return [self visibilityDepth] + 1; +} + +#pragma mark - UIKit overrides + +- (void)setViewControllers:(NSArray<__kindof UIViewController *> *)viewControllers +{ + [super setViewControllers:viewControllers]; + [self visibilityDepthDidChange]; +} + +- (void)setViewControllers:(NSArray<__kindof UIViewController *> *)viewControllers animated:(BOOL)animated +{ + [super setViewControllers:viewControllers animated:animated]; + [self visibilityDepthDidChange]; +} + +- (void)setSelectedIndex:(NSUInteger)selectedIndex +{ + [super setSelectedIndex:selectedIndex]; + [self visibilityDepthDidChange]; +} + +- (void)setSelectedViewController:(__kindof UIViewController *)selectedViewController +{ + [super setSelectedViewController:selectedViewController]; + [self visibilityDepthDidChange]; +} + +@end diff --git a/AsyncDisplayKit/ASViewController.h b/AsyncDisplayKit/ASViewController.h index 4102ee80ba..71a7e4a70c 100644 --- a/AsyncDisplayKit/ASViewController.h +++ b/AsyncDisplayKit/ASViewController.h @@ -8,6 +8,7 @@ #import #import +#import @class ASTraitCollection; @@ -16,7 +17,7 @@ NS_ASSUME_NONNULL_BEGIN typedef ASTraitCollection * _Nonnull (^ASDisplayTraitsForTraitCollectionBlock)(UITraitCollection *traitCollection); typedef ASTraitCollection * _Nonnull (^ASDisplayTraitsForTraitWindowSizeBlock)(CGSize windowSize); -@interface ASViewController<__covariant DisplayNodeType : ASDisplayNode *> : UIViewController +@interface ASViewController<__covariant DisplayNodeType : ASDisplayNode *> : UIViewController - (instancetype)initWithNode:(DisplayNodeType)node NS_DESIGNATED_INITIALIZER; diff --git a/AsyncDisplayKit/ASViewController.mm b/AsyncDisplayKit/ASViewController.mm index db5b1e5b4d..80d8d2ec1b 100644 --- a/AsyncDisplayKit/ASViewController.mm +++ b/AsyncDisplayKit/ASViewController.mm @@ -13,10 +13,14 @@ #import "ASDisplayNode+Beta.h" #import "ASRangeControllerUpdateRangeProtocol+Beta.h" +#define AS_LOG_VISIBILITY_CHANGES 1 + @implementation ASViewController { BOOL _ensureDisplayed; BOOL _automaticallyAdjustRangeModeBasedOnViewEvents; + BOOL _parentManagesVisibilityDepth; + NSInteger _visibilityDepth; } - (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil @@ -81,21 +85,75 @@ [super viewDidLayoutSubviews]; } +- (void)didMoveToParentViewController:(UIViewController *)parent +{ + [super didMoveToParentViewController:parent]; + [self visibilityDepthDidChange]; +} + - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; _ensureDisplayed = YES; [_node measureWithSizeRange:[self nodeConstrainedSize]]; [_node recursivelyFetchData]; - - [self updateCurrentRangeModeWithModeIfPossible:ASLayoutRangeModeFull]; + + if (_parentManagesVisibilityDepth == NO) { + _visibilityDepth = 0; + [self visibilityDepthDidChange]; + } } - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; - [self updateCurrentRangeModeWithModeIfPossible:ASLayoutRangeModeMinimum]; + if (_parentManagesVisibilityDepth == NO) { + _visibilityDepth = 1; + [self visibilityDepthDidChange]; + } +} + +- (NSInteger)visibilityDepth +{ + if (self.parentViewController && _parentManagesVisibilityDepth == NO) { + _parentManagesVisibilityDepth = [self.parentViewController conformsToProtocol:@protocol(ASManagesChildVisibilityDepth)]; + } + + if (_parentManagesVisibilityDepth) { + return [(id )self.parentViewController visibilityDepthOfChildViewController:self]; + } + return _visibilityDepth; +} + +- (void)visibilityDepthDidChange +{ + ASLayoutRangeMode rangeMode = ASLayoutRangeModeForVisibilityDepth(self.visibilityDepth); +#if AS_LOG_VISIBILITY_CHANGES + NSString *rangeModeString; + switch (rangeMode) { + case ASLayoutRangeModeMinimum: + rangeModeString = @"Minimum"; + break; + + case ASLayoutRangeModeFull: + rangeModeString = @"Full"; + break; + + case ASLayoutRangeModeVisibleOnly: + rangeModeString = @"Visible Only"; + break; + + case ASLayoutRangeModeLowMemory: + rangeModeString = @"Low Memory"; + break; + + default: + break; + } + NSLog(@"Updating visibility of:%@ to: %@ (visibility depth: %d)", self, rangeModeString, self.visibilityDepth); +#endif + [self updateCurrentRangeModeWithModeIfPossible:rangeMode]; } #pragma mark - Automatic range mode @@ -113,7 +171,9 @@ - (void)updateCurrentRangeModeWithModeIfPossible:(ASLayoutRangeMode)rangeMode { if (!_automaticallyAdjustRangeModeBasedOnViewEvents) { return; } - if (![_node conformsToProtocol:@protocol(ASRangeControllerUpdateRangeProtocol)]) { return; } + if (![_node conformsToProtocol:@protocol(ASRangeControllerUpdateRangeProtocol)]) { + return; + } id updateRangeNode = (id)_node; [updateRangeNode updateCurrentRangeWithMode:rangeMode]; diff --git a/AsyncDisplayKit/ASVisibilityProtocols.h b/AsyncDisplayKit/ASVisibilityProtocols.h new file mode 100644 index 0000000000..39eb0d53b7 --- /dev/null +++ b/AsyncDisplayKit/ASVisibilityProtocols.h @@ -0,0 +1,45 @@ +// +// ASVisibilityProtocols.h +// Pods +// +// Created by Garrett Moon on 4/27/16. +// +// + +#import "ASLayoutRangeType.h" + +ASLayoutRangeMode ASLayoutRangeModeForVisibilityDepth(NSUInteger visibilityDepth); + +@protocol ASVisibilityDepth + +/** + * @abstract Represents the number of user actions necessary to reach the view controller. An increased visibility + * depth indicates a higher number of user interactions for the view controller to be visible again. For example, + * an onscreen navigation controller's top view controller should have a visibility depth of 0. The view controller + * one from the top should have a visibility deptch of 1 as should the root view controller in the stack (because + * the user can hold the back button to pop to the root view controller). + * + * Visibility depth is used to automatically adjust ranges on range controllers (and thus free up memory) and can + * be used to reduce memory usage of other items as well. + */ +- (NSInteger)visibilityDepth; + + +- (void)visibilityDepthDidChange; + +@end + +/** + * @abstract Container view controllers should adopt this protocol to indicate that they will manage their child's + * visibilityDepth. For example, ASNavigationController adopts this protocol and manages its childrens visibility + * depth. + * + * If you adopt this protocol, you *must* also emit visibilityDepthDidChange messages to child view controllers. + * + * @param childViewController Expected to return the visibility depth of the child view controller. + */ +@protocol ASManagesChildVisibilityDepth + +- (NSInteger)visibilityDepthOfChildViewController:(UIViewController *)childViewController; + +@end diff --git a/AsyncDisplayKit/ASVisibilityProtocols.m b/AsyncDisplayKit/ASVisibilityProtocols.m new file mode 100644 index 0000000000..a739fd0111 --- /dev/null +++ b/AsyncDisplayKit/ASVisibilityProtocols.m @@ -0,0 +1,23 @@ +// +// ASVisibilityProtocols.m +// Pods +// +// Created by Garrett Moon on 4/28/16. +// +// + +#import + +#import "ASVisibilityProtocols.h" + +ASLayoutRangeMode ASLayoutRangeModeForVisibilityDepth(NSUInteger visibilityDepth) +{ + if (visibilityDepth == 0) { + return ASLayoutRangeModeFull; + } else if (visibilityDepth == 1) { + return ASLayoutRangeModeMinimum; + } else if (visibilityDepth == 2) { + return ASLayoutRangeModeVisibleOnly; + } + return ASLayoutRangeModeLowMemory; +} \ No newline at end of file diff --git a/AsyncDisplayKit/AsyncDisplayKit.h b/AsyncDisplayKit/AsyncDisplayKit.h index 42a3baa511..7de390bb98 100644 --- a/AsyncDisplayKit/AsyncDisplayKit.h +++ b/AsyncDisplayKit/AsyncDisplayKit.h @@ -34,6 +34,8 @@ #import #import +#import +#import #import #import @@ -78,6 +80,7 @@ #import #import #import +#import #import From b7b8ad54fd9045944382aa1d36ae621a78cf2524 Mon Sep 17 00:00:00 2001 From: Garrett Moon Date: Wed, 11 May 2016 16:54:38 -0700 Subject: [PATCH 42/52] Move common implementations to macros --- AsyncDisplayKit/ASNavigationController.m | 38 +++------------------ AsyncDisplayKit/ASTabBarController.m | 38 +++------------------ AsyncDisplayKit/ASViewController.mm | 28 ++-------------- AsyncDisplayKit/ASVisibilityProtocols.h | 42 ++++++++++++++++++++++++ 4 files changed, 53 insertions(+), 93 deletions(-) diff --git a/AsyncDisplayKit/ASNavigationController.m b/AsyncDisplayKit/ASNavigationController.m index 7f5af99d6e..2135c8bf59 100644 --- a/AsyncDisplayKit/ASNavigationController.m +++ b/AsyncDisplayKit/ASNavigationController.m @@ -14,43 +14,13 @@ NSInteger _visibilityDepth; } -- (void)didMoveToParentViewController:(UIViewController *)parent -{ - [super didMoveToParentViewController:parent]; - [self visibilityDepthDidChange]; -} +ASVisibilityDidMoveToParentViewController; -- (void)viewWillAppear:(BOOL)animated -{ - [super viewWillAppear:animated]; +ASVisibilityViewWillAppear; - if (_parentManagesVisibilityDepth == NO) { - _visibilityDepth = 0; - [self visibilityDepthDidChange]; - } -} +ASVisibilityViewDidDisappearImplementation; -- (void)viewDidDisappear:(BOOL)animated -{ - [super viewDidDisappear:animated]; - - if (_parentManagesVisibilityDepth == NO) { - _visibilityDepth = 1; - [self visibilityDepthDidChange]; - } -} - -- (NSInteger)visibilityDepth -{ - if (self.parentViewController && _parentManagesVisibilityDepth == NO) { - _parentManagesVisibilityDepth = [self.parentViewController conformsToProtocol:@protocol(ASManagesChildVisibilityDepth)]; - } - - if (_parentManagesVisibilityDepth) { - return [(id )self.parentViewController visibilityDepthOfChildViewController:self]; - } - return _visibilityDepth; -} +ASVisibilityDepthImplementation; - (void)visibilityDepthDidChange { diff --git a/AsyncDisplayKit/ASTabBarController.m b/AsyncDisplayKit/ASTabBarController.m index b083dba7a9..ff06182e90 100644 --- a/AsyncDisplayKit/ASTabBarController.m +++ b/AsyncDisplayKit/ASTabBarController.m @@ -14,43 +14,13 @@ NSInteger _visibilityDepth; } -- (void)didMoveToParentViewController:(UIViewController *)parent -{ - [super didMoveToParentViewController:parent]; - [self visibilityDepthDidChange]; -} +ASVisibilityDidMoveToParentViewController; -- (void)viewWillAppear:(BOOL)animated -{ - [super viewWillAppear:animated]; - - if (_parentManagesVisibilityDepth == NO) { - _visibilityDepth = 0; - [self visibilityDepthDidChange]; - } -} +ASVisibilityViewWillAppear; -- (void)viewDidDisappear:(BOOL)animated -{ - [super viewDidDisappear:animated]; - - if (_parentManagesVisibilityDepth == NO) { - _visibilityDepth = 1; - [self visibilityDepthDidChange]; - } -} +ASVisibilityViewDidDisappearImplementation; -- (NSInteger)visibilityDepth -{ - if (self.parentViewController && _parentManagesVisibilityDepth == NO) { - _parentManagesVisibilityDepth = [self.parentViewController conformsToProtocol:@protocol(ASManagesChildVisibilityDepth)]; - } - - if (_parentManagesVisibilityDepth) { - return [(id )self.parentViewController visibilityDepthOfChildViewController:self]; - } - return _visibilityDepth; -} +ASVisibilityDepthImplementation; - (void)visibilityDepthDidChange { diff --git a/AsyncDisplayKit/ASViewController.mm b/AsyncDisplayKit/ASViewController.mm index 80d8d2ec1b..3166eb0726 100644 --- a/AsyncDisplayKit/ASViewController.mm +++ b/AsyncDisplayKit/ASViewController.mm @@ -85,11 +85,7 @@ [super viewDidLayoutSubviews]; } -- (void)didMoveToParentViewController:(UIViewController *)parent -{ - [super didMoveToParentViewController:parent]; - [self visibilityDepthDidChange]; -} +ASVisibilityDidMoveToParentViewController; - (void)viewWillAppear:(BOOL)animated { @@ -104,27 +100,9 @@ } } -- (void)viewDidDisappear:(BOOL)animated -{ - [super viewDidDisappear:animated]; - - if (_parentManagesVisibilityDepth == NO) { - _visibilityDepth = 1; - [self visibilityDepthDidChange]; - } -} +ASVisibilityViewDidDisappearImplementation; -- (NSInteger)visibilityDepth -{ - if (self.parentViewController && _parentManagesVisibilityDepth == NO) { - _parentManagesVisibilityDepth = [self.parentViewController conformsToProtocol:@protocol(ASManagesChildVisibilityDepth)]; - } - - if (_parentManagesVisibilityDepth) { - return [(id )self.parentViewController visibilityDepthOfChildViewController:self]; - } - return _visibilityDepth; -} +ASVisibilityDepthImplementation; - (void)visibilityDepthDidChange { diff --git a/AsyncDisplayKit/ASVisibilityProtocols.h b/AsyncDisplayKit/ASVisibilityProtocols.h index 39eb0d53b7..955841dbec 100644 --- a/AsyncDisplayKit/ASVisibilityProtocols.h +++ b/AsyncDisplayKit/ASVisibilityProtocols.h @@ -43,3 +43,45 @@ ASLayoutRangeMode ASLayoutRangeModeForVisibilityDepth(NSUInteger visibilityDepth - (NSInteger)visibilityDepthOfChildViewController:(UIViewController *)childViewController; @end + +#define ASVisibilityDepthImplementation \ +- (NSInteger)visibilityDepth \ +{ \ + if (self.parentViewController && _parentManagesVisibilityDepth == NO) { \ + _parentManagesVisibilityDepth = [self.parentViewController conformsToProtocol:@protocol(ASManagesChildVisibilityDepth)]; \ + } \ + \ + if (_parentManagesVisibilityDepth) { \ + return [(id )self.parentViewController visibilityDepthOfChildViewController:self]; \ + } \ + return _visibilityDepth; \ +} + +#define ASVisibilityViewDidDisappearImplementation \ +- (void)viewDidDisappear:(BOOL)animated \ +{ \ + [super viewDidDisappear:animated]; \ + \ + if (_parentManagesVisibilityDepth == NO) { \ + _visibilityDepth = 1; \ + [self visibilityDepthDidChange]; \ + } \ +} + +#define ASVisibilityViewWillAppear \ +- (void)viewWillAppear:(BOOL)animated \ +{ \ + [super viewWillAppear:animated]; \ + \ + if (_parentManagesVisibilityDepth == NO) { \ + _visibilityDepth = 0; \ + [self visibilityDepthDidChange]; \ + } \ +} + +#define ASVisibilityDidMoveToParentViewController \ +- (void)didMoveToParentViewController:(UIViewController *)parent \ +{ \ + [super didMoveToParentViewController:parent]; \ + [self visibilityDepthDidChange]; \ +} From e296cad8ee90933e4b6240b6d92f903cc02da666 Mon Sep 17 00:00:00 2001 From: Garrett Moon Date: Wed, 11 May 2016 16:55:10 -0700 Subject: [PATCH 43/52] Add support for visibility depth Summary: This adds support for the concept of visibility depth. Visibility essentially defines the number of user actions it would take a user to have a view controller visible. Knowing a view controllers visibility depth allows view controllers to take action such as clearing out memory that can be restored at a later date. This patch also add two new view controller subclasses which adopt the ASManagesChildVisibilityDepth protocol. Any view controller that has child view controllers can adopt this protocol to indicate to the child what they're visibility is. For example, ASNavigationController will return a visibility depth of it's own visibilityDepth + 1 for a view controller that would be revealed by tapping the back button. Move common implementations to macros Turn off visibility logging Differential Revision: https://phabricator.pinadmin.com/D90395 --- AsyncDisplayKit/ASViewController.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AsyncDisplayKit/ASViewController.mm b/AsyncDisplayKit/ASViewController.mm index 3166eb0726..a79af042e5 100644 --- a/AsyncDisplayKit/ASViewController.mm +++ b/AsyncDisplayKit/ASViewController.mm @@ -13,7 +13,7 @@ #import "ASDisplayNode+Beta.h" #import "ASRangeControllerUpdateRangeProtocol+Beta.h" -#define AS_LOG_VISIBILITY_CHANGES 1 +#define AS_LOG_VISIBILITY_CHANGES 0 @implementation ASViewController { From 5a9ef8a6f7f85b767f1e0ebf64e7f273dd3f9b46 Mon Sep 17 00:00:00 2001 From: Garrett Moon Date: Wed, 11 May 2016 17:29:09 -0700 Subject: [PATCH 44/52] Fix build --- AsyncDisplayKit.xcodeproj/project.pbxproj | 12 +++++++----- AsyncDisplayKit/ASVisibilityProtocols.h | 2 ++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index 722bae0679..24a82c91dc 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -250,6 +250,7 @@ 509E68661B3AEDD7009B9150 /* CGRect+ASConvenience.m in Sources */ = {isa = PBXBuildFile; fileRef = 205F0E201B376416007741D0 /* CGRect+ASConvenience.m */; }; 636EA1A41C7FF4EC00EE152F /* NSArray+Diffing.m in Sources */ = {isa = PBXBuildFile; fileRef = DBC452DA1C5BF64600B16017 /* NSArray+Diffing.m */; }; 636EA1A51C7FF4EF00EE152F /* ASDefaultPlayButton.m in Sources */ = {isa = PBXBuildFile; fileRef = AEB7B0191C5962EA00662EF4 /* ASDefaultPlayButton.m */; }; + 680346941CE4052A0009FEB4 /* ASNavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = 68FC85DC1CE29AB700EDD713 /* ASNavigationController.h */; settings = {ATTRIBUTES = (Public, ); }; }; 68355B311CB5799E001D4E68 /* ASImageNode+AnimatedImage.mm in Sources */ = {isa = PBXBuildFile; fileRef = 68355B2E1CB5799E001D4E68 /* ASImageNode+AnimatedImage.mm */; }; 68355B341CB579B9001D4E68 /* ASImageNode+AnimatedImage.mm in Sources */ = {isa = PBXBuildFile; fileRef = 68355B2E1CB5799E001D4E68 /* ASImageNode+AnimatedImage.mm */; }; 68355B3A1CB57A5A001D4E68 /* ASPINRemoteImageDownloader.m in Sources */ = {isa = PBXBuildFile; fileRef = 68355B361CB57A5A001D4E68 /* ASPINRemoteImageDownloader.m */; }; @@ -272,15 +273,15 @@ 68EE0DBE1C1B4ED300BA1B99 /* ASMainSerialQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 68EE0DBB1C1B4ED300BA1B99 /* ASMainSerialQueue.h */; }; 68EE0DBF1C1B4ED300BA1B99 /* ASMainSerialQueue.mm in Sources */ = {isa = PBXBuildFile; fileRef = 68EE0DBC1C1B4ED300BA1B99 /* ASMainSerialQueue.mm */; }; 68EE0DC01C1B4ED300BA1B99 /* ASMainSerialQueue.mm in Sources */ = {isa = PBXBuildFile; fileRef = 68EE0DBC1C1B4ED300BA1B99 /* ASMainSerialQueue.mm */; }; - 68FC85DE1CE29AB700EDD713 /* ASNavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = 68FC85DC1CE29AB700EDD713 /* ASNavigationController.h */; }; + 68FC85DE1CE29AB700EDD713 /* ASNavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = 68FC85DC1CE29AB700EDD713 /* ASNavigationController.h */; settings = {ATTRIBUTES = (Public, ); }; }; 68FC85DF1CE29AB700EDD713 /* ASNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 68FC85DD1CE29AB700EDD713 /* ASNavigationController.m */; }; - 68FC85E21CE29B7E00EDD713 /* ASTabBarController.h in Headers */ = {isa = PBXBuildFile; fileRef = 68FC85E01CE29B7E00EDD713 /* ASTabBarController.h */; }; - 68FC85E31CE29B7E00EDD713 /* ASTabBarController.h in Headers */ = {isa = PBXBuildFile; fileRef = 68FC85E01CE29B7E00EDD713 /* ASTabBarController.h */; }; + 68FC85E21CE29B7E00EDD713 /* ASTabBarController.h in Headers */ = {isa = PBXBuildFile; fileRef = 68FC85E01CE29B7E00EDD713 /* ASTabBarController.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 68FC85E31CE29B7E00EDD713 /* ASTabBarController.h in Headers */ = {isa = PBXBuildFile; fileRef = 68FC85E01CE29B7E00EDD713 /* ASTabBarController.h */; settings = {ATTRIBUTES = (Public, ); }; }; 68FC85E41CE29B7E00EDD713 /* ASTabBarController.m in Sources */ = {isa = PBXBuildFile; fileRef = 68FC85E11CE29B7E00EDD713 /* ASTabBarController.m */; }; 68FC85E51CE29B7E00EDD713 /* ASTabBarController.m in Sources */ = {isa = PBXBuildFile; fileRef = 68FC85E11CE29B7E00EDD713 /* ASTabBarController.m */; }; 68FC85E61CE29B9400EDD713 /* ASNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 68FC85DD1CE29AB700EDD713 /* ASNavigationController.m */; }; - 68FC85E91CE29C7D00EDD713 /* ASVisibilityProtocols.h in Headers */ = {isa = PBXBuildFile; fileRef = 68FC85E71CE29C7D00EDD713 /* ASVisibilityProtocols.h */; }; - 68FC85EA1CE29C7D00EDD713 /* ASVisibilityProtocols.h in Headers */ = {isa = PBXBuildFile; fileRef = 68FC85E71CE29C7D00EDD713 /* ASVisibilityProtocols.h */; }; + 68FC85E91CE29C7D00EDD713 /* ASVisibilityProtocols.h in Headers */ = {isa = PBXBuildFile; fileRef = 68FC85E71CE29C7D00EDD713 /* ASVisibilityProtocols.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 68FC85EA1CE29C7D00EDD713 /* ASVisibilityProtocols.h in Headers */ = {isa = PBXBuildFile; fileRef = 68FC85E71CE29C7D00EDD713 /* ASVisibilityProtocols.h */; settings = {ATTRIBUTES = (Public, ); }; }; 68FC85EB1CE29C7D00EDD713 /* ASVisibilityProtocols.m in Sources */ = {isa = PBXBuildFile; fileRef = 68FC85E81CE29C7D00EDD713 /* ASVisibilityProtocols.m */; }; 68FC85EC1CE29C7D00EDD713 /* ASVisibilityProtocols.m in Sources */ = {isa = PBXBuildFile; fileRef = 68FC85E81CE29C7D00EDD713 /* ASVisibilityProtocols.m */; }; 698548631CA9E025008A345F /* ASEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = 698548611CA9E025008A345F /* ASEnvironment.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1713,6 +1714,7 @@ B35062521B010EFD0018CF92 /* ASDisplayNodeInternal.h in Headers */, B35062001B010EFD0018CF92 /* ASEditableTextNode.h in Headers */, B350625B1B010F070018CF92 /* ASEqualityHelpers.h in Headers */, + 680346941CE4052A0009FEB4 /* ASNavigationController.h in Headers */, B350621B1B010EFD0018CF92 /* ASFlowLayoutController.h in Headers */, B350621D1B010EFD0018CF92 /* ASHighlightOverlayLayer.h in Headers */, C78F7E2B1BF7809800CDEAFC /* ASTableNode.h in Headers */, diff --git a/AsyncDisplayKit/ASVisibilityProtocols.h b/AsyncDisplayKit/ASVisibilityProtocols.h index 955841dbec..20c5b5b8f8 100644 --- a/AsyncDisplayKit/ASVisibilityProtocols.h +++ b/AsyncDisplayKit/ASVisibilityProtocols.h @@ -8,6 +8,8 @@ #import "ASLayoutRangeType.h" +@class UIViewController; + ASLayoutRangeMode ASLayoutRangeModeForVisibilityDepth(NSUInteger visibilityDepth); @protocol ASVisibilityDepth From 4c78fb3846c0081dda6c8cf069f57f54130c0159 Mon Sep 17 00:00:00 2001 From: Garrett Moon Date: Thu, 12 May 2016 10:53:20 -0700 Subject: [PATCH 45/52] Add setVisibilityDepth setter. --- AsyncDisplayKit/ASNavigationController.m | 2 ++ AsyncDisplayKit/ASTabBarController.m | 2 ++ AsyncDisplayKit/ASViewController.mm | 5 +++-- AsyncDisplayKit/ASVisibilityProtocols.h | 16 ++++++++++++---- 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/AsyncDisplayKit/ASNavigationController.m b/AsyncDisplayKit/ASNavigationController.m index 2135c8bf59..6b0c3b140b 100644 --- a/AsyncDisplayKit/ASNavigationController.m +++ b/AsyncDisplayKit/ASNavigationController.m @@ -20,6 +20,8 @@ ASVisibilityViewWillAppear; ASVisibilityViewDidDisappearImplementation; +ASVisibilitySetVisibilityDepth; + ASVisibilityDepthImplementation; - (void)visibilityDepthDidChange diff --git a/AsyncDisplayKit/ASTabBarController.m b/AsyncDisplayKit/ASTabBarController.m index ff06182e90..28150f0945 100644 --- a/AsyncDisplayKit/ASTabBarController.m +++ b/AsyncDisplayKit/ASTabBarController.m @@ -20,6 +20,8 @@ ASVisibilityViewWillAppear; ASVisibilityViewDidDisappearImplementation; +ASVisibilitySetVisibilityDepth; + ASVisibilityDepthImplementation; - (void)visibilityDepthDidChange diff --git a/AsyncDisplayKit/ASViewController.mm b/AsyncDisplayKit/ASViewController.mm index a79af042e5..7cb031a11a 100644 --- a/AsyncDisplayKit/ASViewController.mm +++ b/AsyncDisplayKit/ASViewController.mm @@ -95,11 +95,12 @@ ASVisibilityDidMoveToParentViewController; [_node recursivelyFetchData]; if (_parentManagesVisibilityDepth == NO) { - _visibilityDepth = 0; - [self visibilityDepthDidChange]; + [self setVisibilityDepth:0]; } } +ASVisibilitySetVisibilityDepth; + ASVisibilityViewDidDisappearImplementation; ASVisibilityDepthImplementation; diff --git a/AsyncDisplayKit/ASVisibilityProtocols.h b/AsyncDisplayKit/ASVisibilityProtocols.h index 20c5b5b8f8..6301b65f2b 100644 --- a/AsyncDisplayKit/ASVisibilityProtocols.h +++ b/AsyncDisplayKit/ASVisibilityProtocols.h @@ -46,6 +46,16 @@ ASLayoutRangeMode ASLayoutRangeModeForVisibilityDepth(NSUInteger visibilityDepth @end +#define ASVisibilitySetVisibilityDepth \ +- (void)setVisibilityDepth:(NSUInteger)visibilityDepth \ +{ \ + if (_visibilityDepth == visibilityDepth) { \ + return; \ + } \ + _visibilityDepth = visibilityDepth; \ + [self visibilityDepthDidChange]; \ +} + #define ASVisibilityDepthImplementation \ - (NSInteger)visibilityDepth \ { \ @@ -65,8 +75,7 @@ ASLayoutRangeMode ASLayoutRangeModeForVisibilityDepth(NSUInteger visibilityDepth [super viewDidDisappear:animated]; \ \ if (_parentManagesVisibilityDepth == NO) { \ - _visibilityDepth = 1; \ - [self visibilityDepthDidChange]; \ + [self setVisibilityDepth:1]; \ } \ } @@ -76,8 +85,7 @@ ASLayoutRangeMode ASLayoutRangeModeForVisibilityDepth(NSUInteger visibilityDepth [super viewWillAppear:animated]; \ \ if (_parentManagesVisibilityDepth == NO) { \ - _visibilityDepth = 0; \ - [self visibilityDepthDidChange]; \ + [self setVisibilityDepth:0]; \ } \ } From 7901a985e360090aab5e3ef4241c447e70de5984 Mon Sep 17 00:00:00 2001 From: Garrett Moon Date: Thu, 12 May 2016 14:21:01 -0700 Subject: [PATCH 46/52] Now that this is included by a C++ file, it needs the weird C extern thing. --- AsyncDisplayKit/ASVisibilityProtocols.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/AsyncDisplayKit/ASVisibilityProtocols.h b/AsyncDisplayKit/ASVisibilityProtocols.h index 6301b65f2b..c077d8ff2e 100644 --- a/AsyncDisplayKit/ASVisibilityProtocols.h +++ b/AsyncDisplayKit/ASVisibilityProtocols.h @@ -8,9 +8,15 @@ #import "ASLayoutRangeType.h" +#import "ASBaseDefines.h" + @class UIViewController; -ASLayoutRangeMode ASLayoutRangeModeForVisibilityDepth(NSUInteger visibilityDepth); +ASDISPLAYNODE_EXTERN_C_BEGIN + +extern ASLayoutRangeMode ASLayoutRangeModeForVisibilityDepth(NSUInteger visibilityDepth); + +ASDISPLAYNODE_EXTERN_C_END @protocol ASVisibilityDepth From 72d7b57abb02abbffa99cd9905150640a8a8ef9e Mon Sep 17 00:00:00 2001 From: Garrett Moon Date: Thu, 12 May 2016 14:44:54 -0700 Subject: [PATCH 47/52] Don't add zero for readability --- AsyncDisplayKit/ASNavigationController.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AsyncDisplayKit/ASNavigationController.m b/AsyncDisplayKit/ASNavigationController.m index 6b0c3b140b..a246aa33d4 100644 --- a/AsyncDisplayKit/ASNavigationController.m +++ b/AsyncDisplayKit/ASNavigationController.m @@ -39,8 +39,8 @@ ASVisibilityDepthImplementation; NSAssert(viewControllerIndex != NSNotFound, @"childViewController is not in the navigation stack."); if (viewControllerIndex == self.viewControllers.count - 1) { - //view controller is at the top - return [self visibilityDepth] + 0; + //view controller is at the top, just return our own visibility depth. + return [self visibilityDepth]; } else if (viewControllerIndex == 0) { //view controller is the root view controller. Can be accessed by holding the back button. return [self visibilityDepth] + 1; From 8e38e225c8ae0be6408f51c9ee9424ad8c9e139c Mon Sep 17 00:00:00 2001 From: Henish Shah Date: Fri, 13 May 2016 11:51:01 -0400 Subject: [PATCH 48/52] [Sample] Resolve mutation during enumeration issue - Mutating a dictionary using -enumerateKeysAndObjectsUsingBlock: can have unintended consequences. - Using a copy of the keys to iterate over the values inside the dictionary instead. --- AsyncDisplayKit/Details/ASCollectionDataController.mm | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/AsyncDisplayKit/Details/ASCollectionDataController.mm b/AsyncDisplayKit/Details/ASCollectionDataController.mm index 7026024ff8..b264102a9f 100644 --- a/AsyncDisplayKit/Details/ASCollectionDataController.mm +++ b/AsyncDisplayKit/Details/ASCollectionDataController.mm @@ -51,7 +51,9 @@ - (void)willReloadData { - [_pendingContexts enumerateKeysAndObjectsUsingBlock:^(NSString *kind, NSMutableArray *contexts, BOOL *stop) { + NSArray *keys = _pendingContexts.allKeys; + for (NSString *kind in keys) { + NSMutableArray *contexts = _pendingContexts[kind]; // Remove everything that existed before the reload, now that we're ready to insert replacements NSArray *indexPaths = [self indexPathsForEditingNodesOfKind:kind]; [self deleteNodesOfKind:kind atIndexPaths:indexPaths completion:nil]; @@ -72,7 +74,7 @@ [self insertNodes:nodes ofKind:kind atIndexPaths:indexPaths completion:nil]; }]; [_pendingContexts removeObjectForKey:kind]; - }]; + } } - (void)prepareForInsertSections:(NSIndexSet *)sections From 7d902d98c9421cd35251d67981d74c749df31437 Mon Sep 17 00:00:00 2001 From: Michael Schneider Date: Fri, 13 May 2016 21:02:11 +0200 Subject: [PATCH 49/52] Fix passing wrong constrained size to nodes In _layoutNodesFromContexts:ofKind:completion: we pass the full array of contexts to _layoutNodes:fromContexts:atIndexesOfRange:ofKind: but for nodes we pass a subarray of nodes instead based on the batchCount. As batchRange we always start from 0 to batchCount. We now use the same indexes that we use to create the subarray of nodes to get a subarray of contexts that we pass to _layoutNodes:fromContexts:atIndexesOfRange:ofKind:. --- AsyncDisplayKit/Details/ASDataController.mm | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/AsyncDisplayKit/Details/ASDataController.mm b/AsyncDisplayKit/Details/ASDataController.mm index 3271ebb55e..cbe6e763b4 100644 --- a/AsyncDisplayKit/Details/ASDataController.mm +++ b/AsyncDisplayKit/Details/ASDataController.mm @@ -191,14 +191,16 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; for (NSUInteger j = 0; j < nodeCount; j += kASDataControllerSizingCountPerProcessor) { NSInteger batchCount = MIN(kASDataControllerSizingCountPerProcessor, nodeCount - j); - __block NSArray *subarray; + // Get subcontexts for the range of nodes that will be allocated + NSArray *subcontexts = [contexts subarrayWithRange:NSMakeRange(j, batchCount)]; + // Allocate nodes concurrently. + __block NSArray *subarray; dispatch_block_t allocationBlock = ^{ __strong ASCellNode **allocatedNodeBuffer = (__strong ASCellNode **)calloc(batchCount, sizeof(ASCellNode *)); dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_apply(batchCount, queue, ^(size_t i) { - unsigned long k = j + i; - ASCellNode *node = [contexts[k] allocateNode]; + ASCellNode *node = [subcontexts[i] allocateNode]; if (node == nil) { ASDisplayNodeAssertNotNil(node, @"Node block created nil node; %@, %@", self, self.dataSource); node = [[ASCellNode alloc] init]; // Fallback to avoid crash for production apps. @@ -225,11 +227,11 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; }); dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); - [self _layoutNodes:subarray fromContexts:contexts atIndexesOfRange:batchRange ofKind:kind]; + [self _layoutNodes:subarray fromContexts:subcontexts atIndexesOfRange:batchRange ofKind:kind]; } else { allocationBlock(); [_mainSerialQueue performBlockOnMainThread:^{ - [self _layoutNodes:subarray fromContexts:contexts atIndexesOfRange:batchRange ofKind:kind]; + [self _layoutNodes:subarray fromContexts:subcontexts atIndexesOfRange:batchRange ofKind:kind]; }]; } From 33b76bbce0991e43055b91c63e7982c1472a222c Mon Sep 17 00:00:00 2001 From: Michael Schneider Date: Fri, 13 May 2016 21:38:25 +0200 Subject: [PATCH 50/52] =?UTF-8?q?Use=20calloc=E2=80=99d=20array=20for=20su?= =?UTF-8?q?barray=20of=20contexts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AsyncDisplayKit/Details/ASDataController.mm | 26 ++++++++++++--------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/AsyncDisplayKit/Details/ASDataController.mm b/AsyncDisplayKit/Details/ASDataController.mm index cbe6e763b4..2847abf6d6 100644 --- a/AsyncDisplayKit/Details/ASDataController.mm +++ b/AsyncDisplayKit/Details/ASDataController.mm @@ -190,29 +190,33 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; for (NSUInteger j = 0; j < nodeCount; j += kASDataControllerSizingCountPerProcessor) { NSInteger batchCount = MIN(kASDataControllerSizingCountPerProcessor, nodeCount - j); - - // Get subcontexts for the range of nodes that will be allocated - NSArray *subcontexts = [contexts subarrayWithRange:NSMakeRange(j, batchCount)]; - + // Allocate nodes concurrently. - __block NSArray *subarray; + __block NSArray *subarrayOfContexts; + __block NSArray *subarrayOfNodes; dispatch_block_t allocationBlock = ^{ + __strong ASIndexedNodeContext **allocatedContextBuffer = (__strong ASIndexedNodeContext **)calloc(batchCount, sizeof(ASIndexedNodeContext *)); __strong ASCellNode **allocatedNodeBuffer = (__strong ASCellNode **)calloc(batchCount, sizeof(ASCellNode *)); dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_apply(batchCount, queue, ^(size_t i) { - ASCellNode *node = [subcontexts[i] allocateNode]; + unsigned long k = j + i; + ASIndexedNodeContext *context = contexts[k]; + ASCellNode *node = [context allocateNode]; if (node == nil) { ASDisplayNodeAssertNotNil(node, @"Node block created nil node; %@, %@", self, self.dataSource); node = [[ASCellNode alloc] init]; // Fallback to avoid crash for production apps. } allocatedNodeBuffer[i] = node; + allocatedContextBuffer[i] = context; }); - subarray = [[NSArray alloc] initWithObjects:allocatedNodeBuffer count:batchCount]; - + subarrayOfNodes = [[NSArray alloc] initWithObjects:allocatedNodeBuffer count:batchCount]; + subarrayOfContexts = [NSArray arrayWithObjects:allocatedContextBuffer count:batchCount]; // Nil out buffer indexes to allow arc to free the stored cells. for (int i = 0; i < batchCount; i++) { + allocatedContextBuffer[i] = nil; allocatedNodeBuffer[i] = nil; } + free(allocatedContextBuffer); free(allocatedNodeBuffer); }; @@ -227,15 +231,15 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; }); dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); - [self _layoutNodes:subarray fromContexts:subcontexts atIndexesOfRange:batchRange ofKind:kind]; + [self _layoutNodes:subarrayOfNodes fromContexts:subarrayOfContexts atIndexesOfRange:batchRange ofKind:kind]; } else { allocationBlock(); [_mainSerialQueue performBlockOnMainThread:^{ - [self _layoutNodes:subarray fromContexts:subcontexts atIndexesOfRange:batchRange ofKind:kind]; + [self _layoutNodes:subarrayOfNodes fromContexts:subarrayOfContexts atIndexesOfRange:batchRange ofKind:kind]; }]; } - [allocatedNodes addObjectsFromArray:subarray]; + [allocatedNodes addObjectsFromArray:subarrayOfNodes]; dispatch_group_async(layoutGroup, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // We should already have measured loaded nodes before we left the main thread. Layout the remaining ones on a background thread. From 41a53887d74dbb3173db8ca09c4fc8cb96e8b2d3 Mon Sep 17 00:00:00 2001 From: Henish Shah Date: Fri, 13 May 2016 11:51:01 -0400 Subject: [PATCH 51/52] [Sample] Resolve mutation during enumeration issue - Mutating a dictionary using -enumerateKeysAndObjectsUsingBlock: can have unintended consequences. - Using a copy of the keys to iterate over the values inside the dictionary instead. --- .../Details/ASCollectionDataController.mm | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/AsyncDisplayKit/Details/ASCollectionDataController.mm b/AsyncDisplayKit/Details/ASCollectionDataController.mm index b264102a9f..ba1647a282 100644 --- a/AsyncDisplayKit/Details/ASCollectionDataController.mm +++ b/AsyncDisplayKit/Details/ASCollectionDataController.mm @@ -89,7 +89,9 @@ - (void)willInsertSections:(NSIndexSet *)sections { - [_pendingContexts enumerateKeysAndObjectsUsingBlock:^(NSString *kind, NSMutableArray *contexts, BOOL *stop) { + NSArray *keys = _pendingContexts.allKeys; + for (NSString *kind in keys) { + NSMutableArray *contexts = _pendingContexts[kind]; NSMutableArray *sectionArray = [NSMutableArray arrayWithCapacity:sections.count]; for (NSUInteger i = 0; i < sections.count; i++) { [sectionArray addObject:[NSMutableArray array]]; @@ -100,7 +102,7 @@ [self insertNodes:nodes ofKind:kind atIndexPaths:indexPaths completion:nil]; }]; [_pendingContexts removeObjectForKey:kind]; - }]; + } } - (void)willDeleteSections:(NSIndexSet *)sections @@ -124,7 +126,9 @@ - (void)willReloadSections:(NSIndexSet *)sections { - [_pendingContexts enumerateKeysAndObjectsUsingBlock:^(NSString *kind, NSMutableArray *contexts, BOOL *stop) { + NSArray *keys = _pendingContexts.allKeys; + for (NSString *kind in keys) { + NSMutableArray *contexts = _pendingContexts[kind]; NSArray *indexPaths = ASIndexPathsForMultidimensionalArrayAtIndexSet([self editingNodesOfKind:kind], sections); [self deleteNodesOfKind:kind atIndexPaths:indexPaths completion:nil]; // reinsert the elements @@ -132,7 +136,7 @@ [self insertNodes:nodes ofKind:kind atIndexPaths:indexPaths completion:nil]; }]; [_pendingContexts removeObjectForKey:kind]; - }]; + } } - (void)willMoveSection:(NSInteger)section toSection:(NSInteger)newSection From eee226226239ef306d1f143d5c68cd74170b6d27 Mon Sep 17 00:00:00 2001 From: Michael Schneider Date: Fri, 13 May 2016 22:51:40 +0200 Subject: [PATCH 52/52] Match creation of subarrays for nodes and contexts in ASDataController --- AsyncDisplayKit/Details/ASDataController.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AsyncDisplayKit/Details/ASDataController.mm b/AsyncDisplayKit/Details/ASDataController.mm index 2847abf6d6..611dd1c5d3 100644 --- a/AsyncDisplayKit/Details/ASDataController.mm +++ b/AsyncDisplayKit/Details/ASDataController.mm @@ -209,7 +209,7 @@ static void *kASSizingQueueContext = &kASSizingQueueContext; allocatedNodeBuffer[i] = node; allocatedContextBuffer[i] = context; }); - subarrayOfNodes = [[NSArray alloc] initWithObjects:allocatedNodeBuffer count:batchCount]; + subarrayOfNodes = [NSArray arrayWithObjects:allocatedNodeBuffer count:batchCount]; subarrayOfContexts = [NSArray arrayWithObjects:allocatedContextBuffer count:batchCount]; // Nil out buffer indexes to allow arc to free the stored cells. for (int i = 0; i < batchCount; i++) {