From dc3be352af1b057d49391c710b7bfa72b07a50ba Mon Sep 17 00:00:00 2001 From: Huy Nguyen Date: Thu, 10 Aug 2017 17:47:26 +0100 Subject: [PATCH 1/5] [ASTableNode][ASCollectionNode] Add content offset bridging property (#460) - Add content offset bridging property to table and collection node - And use it in `ASCollectionLayout` to avoid measuring unrelated nodes during the first layout. - Update CHANGELOG and highlight deprecated methods --- CHANGELOG.md | 1 + Source/ASCollectionNode.h | 14 ++++++++ Source/ASCollectionNode.mm | 30 +++++++++++++++++ Source/ASCollectionView.h | 7 ++++ Source/ASTableNode.h | 14 ++++++++ Source/ASTableNode.mm | 32 +++++++++++++++++++ Source/ASTableView.h | 18 +++++++---- Source/Details/ASCollectionLayoutContext.h | 1 + Source/Details/ASCollectionLayoutContext.m | 7 ++-- Source/Private/ASCollectionLayout.mm | 6 ++-- .../ASCollectionLayoutContext+Private.h | 1 + .../Private/ASCollectionView+Undeprecated.h | 4 +++ Source/Private/ASTableView+Undeprecated.h | 32 +++++++++---------- Tests/ASPagerNodeTests.m | 17 +++++++--- Tests/ASTableViewTests.mm | 4 +-- 15 files changed, 154 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f4bf0db81..3751a2a20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ - Fix an issue that causes calculatedLayoutDidChange being called needlessly. [Huy Nguyen](https://github.com/nguyenhuy) [#490](https://github.com/TextureGroup/Texture/pull/490) - Negate iOS 11 automatic estimated table row heights. [Christian Selig](https://github.com/christianselig) [#485](https://github.com/TextureGroup/Texture/pull/485) - Rename ASCellNode.viewModel to ASCellNode.nodeViewModel to reduce collisions with subclass properties implemented by clients. [Adlai Holler](https://github.com/Adlai-Holler) [#499](https://github.com/TextureGroup/Texture/pull/499) +- [Breaking] Add content offset bridging property to ASTableNode and ASCollectionNode. Deprecate related methods in ASTableView and ASCollectionView [Huy Nguyen](https://github.com/nguyenhuy) [#460](https://github.com/TextureGroup/Texture/pull/460) ##2.3.5 - Fix an issue where inserting/deleting sections could lead to inconsistent supplementary element behavior. [Adlai Holler](https://github.com/Adlai-Holler) diff --git a/Source/ASCollectionNode.h b/Source/ASCollectionNode.h index 22f4ae601..0ca893c2d 100644 --- a/Source/ASCollectionNode.h +++ b/Source/ASCollectionNode.h @@ -128,6 +128,20 @@ NS_ASSUME_NONNULL_BEGIN */ @property (nonatomic, weak) id layoutInspector; +/** + * The offset of the content view's origin from the collection node's origin. Defaults to CGPointZero. + */ +@property (nonatomic, assign) CGPoint contentOffset; + +/** + * Sets the offset from the content node’s origin to the collection node’s origin. + * + * @param contentOffset The offset + * + * @param animated YES to animate to this new offset at a constant velocity, NO to not aniamte and immediately make the transition. + */ +- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated; + /** * Tuning parameters for a range type in full mode. * diff --git a/Source/ASCollectionNode.mm b/Source/ASCollectionNode.mm index 81c9a907a..b867a0ea9 100644 --- a/Source/ASCollectionNode.mm +++ b/Source/ASCollectionNode.mm @@ -49,6 +49,8 @@ @interface _ASCollectionPendingState : NSObject @property (nonatomic, assign) BOOL usesSynchronousDataLoading; @property (nonatomic, assign) CGFloat leadingScreensForBatching; @property (weak, nonatomic) id layoutInspector; +@property (nonatomic, assign) CGPoint contentOffset; +@property (nonatomic, assign) BOOL animatesContentOffset; @end @implementation _ASCollectionPendingState @@ -61,6 +63,8 @@ - (instancetype)init _allowsSelection = YES; _allowsMultipleSelection = NO; _inverted = NO; + _contentOffset = CGPointZero; + _animatesContentOffset = NO; } return self; } @@ -189,6 +193,8 @@ - (void)didLoad if (pendingState.rangeMode != ASLayoutRangeModeUnspecified) { [view.rangeController updateCurrentRangeWithMode:pendingState.rangeMode]; } + + [view setContentOffset:pendingState.contentOffset animated:pendingState.animatesContentOffset]; // Don't need to set collectionViewLayout to the view as the layout was already used to init the view in view block. } @@ -434,6 +440,30 @@ - (UICollectionViewLayout *)collectionViewLayout } } +- (void)setContentOffset:(CGPoint)contentOffset +{ + [self setContentOffset:contentOffset animated:NO]; +} + +- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated +{ + if ([self pendingState]) { + _pendingState.contentOffset = contentOffset; + _pendingState.animatesContentOffset = animated; + } else { + [self.view setContentOffset:contentOffset animated:animated]; + } +} + +- (CGPoint)contentOffset +{ + if ([self pendingState]) { + return _pendingState.contentOffset; + } else { + return self.view.contentOffset; + } +} + - (ASScrollDirection)scrollDirection { return [self isNodeLoaded] ? self.view.scrollDirection : ASScrollDirectionNone; diff --git a/Source/ASCollectionView.h b/Source/ASCollectionView.h index b2f015cf5..f4dd89138 100644 --- a/Source/ASCollectionView.h +++ b/Source/ASCollectionView.h @@ -141,6 +141,11 @@ NS_ASSUME_NONNULL_BEGIN */ @property (nonatomic) BOOL zeroContentInsets ASDISPLAYNODE_DEPRECATED_MSG("Set automaticallyAdjustsScrollViewInsets=NO on your view controller instead."); +/** + * The point at which the origin of the content view is offset from the origin of the collection view. + */ +@property (nonatomic, assign) CGPoint contentOffset ASDISPLAYNODE_DEPRECATED_MSG("Use ASCollectionNode property instead."); + /** * The object that acts as the asynchronous delegate of the collection view * @@ -407,6 +412,8 @@ NS_ASSUME_NONNULL_BEGIN */ - (NSArray<__kindof ASCellNode *> *)visibleNodes AS_WARN_UNUSED_RESULT ASDISPLAYNODE_DEPRECATED_MSG("Use ASCollectionNode method instead."); +- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated ASDISPLAYNODE_DEPRECATED_MSG("Use ASCollectionNode method instead."); + @end ASDISPLAYNODE_DEPRECATED_MSG("Renamed to ASCollectionDataSource.") diff --git a/Source/ASTableNode.h b/Source/ASTableNode.h index 59fb7183e..20d59d2e3 100644 --- a/Source/ASTableNode.h +++ b/Source/ASTableNode.h @@ -55,6 +55,20 @@ NS_ASSUME_NONNULL_BEGIN */ @property (nonatomic, assign) BOOL inverted; +/** + * The offset of the content view's origin from the table node's origin. Defaults to CGPointZero. + */ +@property (nonatomic, assign) CGPoint contentOffset; + +/** + * Sets the offset from the content node’s origin to the table node’s origin. + * + * @param contentOffset The offset + * + * @param animated YES to animate to this new offset at a constant velocity, NO to not aniamte and immediately make the transition. + */ +- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated; + /** * YES to automatically adjust the contentOffset when cells are inserted or deleted above * visible cells, maintaining the users' visible scroll position. diff --git a/Source/ASTableNode.mm b/Source/ASTableNode.mm index a6e7d8e97..4cd7fd923 100644 --- a/Source/ASTableNode.mm +++ b/Source/ASTableNode.mm @@ -43,6 +43,8 @@ @interface _ASTablePendingState : NSObject @property (nonatomic, assign) BOOL allowsMultipleSelectionDuringEditing; @property (nonatomic, assign) BOOL inverted; @property (nonatomic, assign) CGFloat leadingScreensForBatching; +@property (nonatomic, assign) CGPoint contentOffset; +@property (nonatomic, assign) BOOL animatesContentOffset; @property (nonatomic, assign) BOOL automaticallyAdjustsContentOffset; @end @@ -58,6 +60,8 @@ - (instancetype)init _allowsMultipleSelectionDuringEditing = NO; _inverted = NO; _leadingScreensForBatching = 2; + _contentOffset = CGPointZero; + _animatesContentOffset = NO; _automaticallyAdjustsContentOffset = NO; } return self; @@ -120,6 +124,7 @@ - (void)didLoad if (pendingState.rangeMode != ASLayoutRangeModeUnspecified) { [view.rangeController updateCurrentRangeWithMode:pendingState.rangeMode]; } + [view setContentOffset:pendingState.contentOffset animated:pendingState.animatesContentOffset]; } } @@ -232,6 +237,33 @@ - (CGFloat)leadingScreensForBatching } } +- (void)setContentOffset:(CGPoint)contentOffset +{ + [self setContentOffset:contentOffset animated:NO]; +} + +- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated +{ + _ASTablePendingState *pendingState = self.pendingState; + if (pendingState) { + pendingState.contentOffset = contentOffset; + pendingState.animatesContentOffset = animated; + } else { + ASDisplayNodeAssert(self.nodeLoaded, @"ASTableNode should be loaded if pendingState doesn't exist"); + [self.view setContentOffset:contentOffset animated:animated]; + } +} + +- (CGPoint)contentOffset +{ + _ASTablePendingState *pendingState = self.pendingState; + if (pendingState) { + return pendingState.contentOffset; + } else { + return self.view.contentOffset; + } +} + - (void)setAutomaticallyAdjustsContentOffset:(BOOL)automaticallyAdjustsContentOffset { _ASTablePendingState *pendingState = self.pendingState; diff --git a/Source/ASTableView.h b/Source/ASTableView.h index eb0c92c98..5877ab4d6 100644 --- a/Source/ASTableView.h +++ b/Source/ASTableView.h @@ -67,6 +67,10 @@ NS_ASSUME_NONNULL_BEGIN */ @property (nonatomic, assign) CGFloat leadingScreensForBatching ASDISPLAYNODE_DEPRECATED_MSG("Use ASTableNode property instead."); +/** + * The offset of the content view's origin from the table node's origin. Defaults to CGPointZero. + */ +@property (nonatomic, assign) CGPoint contentOffset ASDISPLAYNODE_DEPRECATED_MSG("Use ASTableNode property instead."); /** * YES to automatically adjust the contentOffset when cells are inserted or deleted above @@ -84,6 +88,12 @@ NS_ASSUME_NONNULL_BEGIN */ @property (nonatomic, assign) BOOL inverted ASDISPLAYNODE_DEPRECATED_MSG("Use ASTableNode property instead."); +@property (nonatomic, readonly, nullable) NSIndexPath *indexPathForSelectedRow ASDISPLAYNODE_DEPRECATED_MSG("Use ASTableNode property instead."); + +@property (nonatomic, readonly, nullable) NSArray *indexPathsForSelectedRows ASDISPLAYNODE_DEPRECATED_MSG("Use ASTableNode property instead."); + +@property (nonatomic, readonly, nullable) NSArray *indexPathsForVisibleRows ASDISPLAYNODE_DEPRECATED_MSG("Use ASTableNode property instead."); + /** * Tuning parameters for a range type in full mode. * @@ -138,12 +148,6 @@ NS_ASSUME_NONNULL_BEGIN - (void)selectRowAtIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated scrollPosition:(UITableViewScrollPosition)scrollPosition ASDISPLAYNODE_DEPRECATED_MSG("Use ASTableNode method instead."); -@property (nonatomic, readonly, nullable) NSIndexPath *indexPathForSelectedRow ASDISPLAYNODE_DEPRECATED_MSG("Use ASTableNode property instead."); - -@property (nonatomic, readonly, nullable) NSArray *indexPathsForSelectedRows ASDISPLAYNODE_DEPRECATED_MSG("Use ASTableNode property instead."); - -@property (nonatomic, readonly, nullable) NSArray *indexPathsForVisibleRows ASDISPLAYNODE_DEPRECATED_MSG("Use ASTableNode property instead."); - - (nullable NSIndexPath *)indexPathForRowAtPoint:(CGPoint)point ASDISPLAYNODE_DEPRECATED_MSG("Use ASTableNode method instead."); - (nullable NSArray *)indexPathsForRowsInRect:(CGRect)rect ASDISPLAYNODE_DEPRECATED_MSG("Use ASTableNode method instead."); @@ -241,6 +245,8 @@ NS_ASSUME_NONNULL_BEGIN /// Deprecated in 2.0. You should not call this method. - (void)clearFetchedData ASDISPLAYNODE_DEPRECATED_MSG("You should not call this method directly. Intead, rely on the Interstate State callback methods."); +- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated ASDISPLAYNODE_DEPRECATED_MSG("Use ASTableNode method instead."); + @end ASDISPLAYNODE_DEPRECATED_MSG("Renamed to ASTableDataSource.") diff --git a/Source/Details/ASCollectionLayoutContext.h b/Source/Details/ASCollectionLayoutContext.h index a20873a81..5c2fdbcab 100644 --- a/Source/Details/ASCollectionLayoutContext.h +++ b/Source/Details/ASCollectionLayoutContext.h @@ -27,6 +27,7 @@ AS_SUBCLASSING_RESTRICTED @interface ASCollectionLayoutContext : NSObject @property (nonatomic, assign, readonly) CGSize viewportSize; +@property (nonatomic, assign, readonly) CGPoint initialContentOffset; @property (nonatomic, assign, readonly) ASScrollDirection scrollableDirections; @property (nonatomic, weak, readonly) ASElementMap *elements; @property (nonatomic, strong, readonly, nullable) id additionalInfo; diff --git a/Source/Details/ASCollectionLayoutContext.m b/Source/Details/ASCollectionLayoutContext.m index eff48afb6..06dcd08f9 100644 --- a/Source/Details/ASCollectionLayoutContext.m +++ b/Source/Details/ASCollectionLayoutContext.m @@ -22,13 +22,11 @@ @implementation ASCollectionLayoutContext { Class _layoutDelegateClass; - - // This ivar doesn't directly involve in the layout calculation process, i.e contexts can be equal regardless of the layout caches. - // As a result, this ivar is ignored in -isEqualToContext: and -hash. __weak ASCollectionLayoutCache *_layoutCache; } - (instancetype)initWithViewportSize:(CGSize)viewportSize + initialContentOffset:(CGPoint)initialContentOffset scrollableDirections:(ASScrollDirection)scrollableDirections elements:(ASElementMap *)elements layoutDelegateClass:(Class)layoutDelegateClass @@ -38,6 +36,7 @@ - (instancetype)initWithViewportSize:(CGSize)viewportSize self = [super init]; if (self) { _viewportSize = viewportSize; + _initialContentOffset = initialContentOffset; _scrollableDirections = scrollableDirections; _elements = elements; _layoutDelegateClass = layoutDelegateClass; @@ -57,6 +56,8 @@ - (ASCollectionLayoutCache *)layoutCache return _layoutCache; } +// NOTE: Some properties, like initialContentOffset and layoutCache are ignored in -isEqualToContext: and -hash. +// That is because contexts can be equal regardless of the content offsets or layout caches. - (BOOL)isEqualToContext:(ASCollectionLayoutContext *)context { if (context == nil) { diff --git a/Source/Private/ASCollectionLayout.mm b/Source/Private/ASCollectionLayout.mm index 2ecc312c7..e8ade9feb 100644 --- a/Source/Private/ASCollectionLayout.mm +++ b/Source/Private/ASCollectionLayout.mm @@ -70,11 +70,13 @@ - (ASCollectionLayoutContext *)layoutContextWithElements:(ASElementMap *)element { ASDisplayNodeAssertMainThread(); CGSize viewportSize = [self _viewportSize]; + CGPoint contentOffset = _collectionNode.contentOffset; id additionalInfo = nil; if (_layoutDelegateFlags.implementsAdditionalInfoForLayoutWithElements) { additionalInfo = [_layoutDelegate additionalInfoForLayoutWithElements:elements]; } return [[ASCollectionLayoutContext alloc] initWithViewportSize:viewportSize + initialContentOffset:contentOffset scrollableDirections:[_layoutDelegate scrollableDirections] elements:elements layoutDelegateClass:[_layoutDelegate class] @@ -93,8 +95,8 @@ + (ASCollectionLayoutState *)calculateLayoutWithContext:(ASCollectionLayoutConte // Measure elements in the measure range ahead of time, block on the initial rect as it'll be visible shortly CGSize viewportSize = context.viewportSize; - // TODO Consider content offset of the collection node - CGRect initialRect = CGRectMake(0, 0, viewportSize.width, viewportSize.height); + CGPoint contentOffset = context.initialContentOffset; + CGRect initialRect = CGRectMake(contentOffset.x, contentOffset.y, viewportSize.width, viewportSize.height); CGRect measureRect = CGRectExpandToRangeWithScrollableDirections(initialRect, kASDefaultMeasureRangeTuningParameters, context.scrollableDirections, diff --git a/Source/Private/ASCollectionLayoutContext+Private.h b/Source/Private/ASCollectionLayoutContext+Private.h index 3c615aef2..0c6686e51 100644 --- a/Source/Private/ASCollectionLayoutContext+Private.h +++ b/Source/Private/ASCollectionLayoutContext+Private.h @@ -28,6 +28,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, weak, readonly) ASCollectionLayoutCache *layoutCache; - (instancetype)initWithViewportSize:(CGSize)viewportSize + initialContentOffset:(CGPoint)initialContentOffset scrollableDirections:(ASScrollDirection)scrollableDirections elements:(ASElementMap *)elements layoutDelegateClass:(Class)layoutDelegateClass diff --git a/Source/Private/ASCollectionView+Undeprecated.h b/Source/Private/ASCollectionView+Undeprecated.h index be3a3f1a0..811ba7baf 100644 --- a/Source/Private/ASCollectionView+Undeprecated.h +++ b/Source/Private/ASCollectionView+Undeprecated.h @@ -75,6 +75,8 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, weak) id layoutInspector; +@property (nonatomic, assign) CGPoint contentOffset; + /** * Tuning parameters for a range type in full mode. * @@ -292,6 +294,8 @@ NS_ASSUME_NONNULL_BEGIN */ - (nullable NSIndexPath *)indexPathForNode:(ASCellNode *)cellNode AS_WARN_UNUSED_RESULT; +- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated; + @end NS_ASSUME_NONNULL_END diff --git a/Source/Private/ASTableView+Undeprecated.h b/Source/Private/ASTableView+Undeprecated.h index f7d0d2a26..70098940f 100644 --- a/Source/Private/ASTableView+Undeprecated.h +++ b/Source/Private/ASTableView+Undeprecated.h @@ -33,6 +33,19 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, weak) id asyncDelegate; @property (nonatomic, weak) id asyncDataSource; +@property (nonatomic, assign) CGPoint contentOffset; +@property (nonatomic, assign) BOOL automaticallyAdjustsContentOffset; +@property (nonatomic, assign) BOOL inverted; +@property (nonatomic, readonly, nullable) NSArray *indexPathsForVisibleRows; +@property (nonatomic, readonly, nullable) NSArray *indexPathsForSelectedRows; +@property (nonatomic, readonly, nullable) NSIndexPath *indexPathForSelectedRow; + +/** + * The number of screens left to scroll before the delegate -tableView:beginBatchFetchingWithContext: is called. + * + * Defaults to two screenfuls. + */ +@property (nonatomic, assign) CGFloat leadingScreensForBatching; /** * Initializer. @@ -44,10 +57,6 @@ NS_ASSUME_NONNULL_BEGIN */ - (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style; -@property (nonatomic, assign) BOOL automaticallyAdjustsContentOffset; - -@property (nonatomic, assign) BOOL inverted; - /** * Tuning parameters for a range type in full mode. * @@ -109,12 +118,6 @@ NS_ASSUME_NONNULL_BEGIN - (void)selectRowAtIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated scrollPosition:(UITableViewScrollPosition)scrollPosition; -@property (nonatomic, readonly, nullable) NSArray *indexPathsForVisibleRows; - -@property (nonatomic, readonly, nullable) NSArray *indexPathsForSelectedRows; - -@property (nonatomic, readonly, nullable) NSIndexPath *indexPathForSelectedRow; - - (nullable NSIndexPath *)indexPathForRowAtPoint:(CGPoint)point; - (nullable NSArray *)indexPathsForRowsInRect:(CGRect)rect; @@ -135,13 +138,6 @@ NS_ASSUME_NONNULL_BEGIN */ - (nullable NSIndexPath *)indexPathForNode:(ASCellNode *)cellNode AS_WARN_UNUSED_RESULT; -/** - * The number of screens left to scroll before the delegate -tableView:beginBatchFetchingWithContext: is called. - * - * Defaults to two screenfuls. - */ -@property (nonatomic, assign) CGFloat leadingScreensForBatching; - /** * Reload everything from scratch, destroying the working range and all cached nodes. * @@ -311,5 +307,7 @@ NS_ASSUME_NONNULL_BEGIN */ - (void)moveRowAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath; +- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated; + @end NS_ASSUME_NONNULL_END diff --git a/Tests/ASPagerNodeTests.m b/Tests/ASPagerNodeTests.m index 428247c53..4b45a8c1e 100644 --- a/Tests/ASPagerNodeTests.m +++ b/Tests/ASPagerNodeTests.m @@ -2,8 +2,17 @@ // ASPagerNodeTests.m // Texture // -// Created by Luke Parham on 11/6/16. -// Copyright © 2016 Facebook. All rights reserved. +// 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 /ASDK-Licenses directory of this source tree. An additional +// grant of patent rights can be found in the PATENTS file in the same directory. +// +// Modifications to this file made after 4/13/2017 are: Copyright (c) 2017-present, +// Pinterest, Inc. Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 // #import @@ -128,7 +137,7 @@ - (void)DISABLED_testThatRootPagerNodeDoesGetTheRightInsetWhilePoppingBack #pragma clang diagnostic pop XCTAssertEqualObjects(NSStringFromCGRect(window.bounds), NSStringFromCGRect(node.frame)); XCTAssertEqualObjects(NSStringFromCGRect(window.bounds), NSStringFromCGRect(cell.frame)); - XCTAssertEqual(pagerNode.view.contentOffset.y, 0); + XCTAssertEqual(pagerNode.contentOffset.y, 0); XCTAssertEqual(pagerNode.view.contentInset.top, 0); e = [self expectationWithDescription:@"Transition completed"]; @@ -158,7 +167,7 @@ - (void)DISABLED_testThatRootPagerNodeDoesGetTheRightInsetWhilePoppingBack #pragma clang diagnostic pop XCTAssertEqualObjects(NSStringFromCGRect(window.bounds), NSStringFromCGRect(node.frame)); XCTAssertEqualObjects(NSStringFromCGRect(window.bounds), NSStringFromCGRect(cell.frame)); - XCTAssertEqual(pagerNode.view.contentOffset.y, 0); + XCTAssertEqual(pagerNode.contentOffset.y, 0); XCTAssertEqual(pagerNode.view.contentInset.top, 0); } diff --git a/Tests/ASTableViewTests.mm b/Tests/ASTableViewTests.mm index 6c53fc849..e7388ccf7 100644 --- a/Tests/ASTableViewTests.mm +++ b/Tests/ASTableViewTests.mm @@ -815,7 +815,7 @@ - (void)testAutomaticallyAdjustingContentOffset [node waitUntilAllUpdatesAreCommitted]; CGFloat rowHeight = [node.view rectForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]].size.height; // Scroll to row (0,1) + 10pt - node.view.contentOffset = CGPointMake(0, rowHeight + 10); + node.contentOffset = CGPointMake(0, rowHeight + 10); [node performBatchAnimated:NO updates:^{ // Delete row 0 from all sections. @@ -829,7 +829,7 @@ - (void)testAutomaticallyAdjustingContentOffset // Now that row (0,0) is deleted, we should have slid up to be at just 10 // i.e. we should have subtracted the deleted row height from our content offset. - XCTAssertEqual(node.view.contentOffset.y, 10); + XCTAssertEqual(node.contentOffset.y, 10); } @end From f58b0b3cd384bee69cc9136b4985440ebc12c0c4 Mon Sep 17 00:00:00 2001 From: Adlai Holler Date: Thu, 10 Aug 2017 16:11:12 -0700 Subject: [PATCH 2/5] Rename the field again to nodeModel (#504) * Rename the field to nodeModel * A few more instances * Fix method name --- CHANGELOG.md | 2 +- Source/ASCellNode.h | 6 +- Source/ASCellNode.mm | 4 +- Source/ASCollectionNode.h | 8 +-- Source/ASCollectionNode.mm | 4 +- Source/ASCollectionView.mm | 10 ++-- Source/ASTableView.mm | 2 +- Source/Details/ASCollectionElement.h | 4 +- Source/Details/ASCollectionElement.mm | 6 +- Source/Details/ASDataController.h | 2 +- Source/Details/ASDataController.mm | 12 ++-- Tests/ASCollectionModernDataSourceTests.m | 72 +++++++++++------------ 12 files changed, 66 insertions(+), 66 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3751a2a20..137725629 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ - Add -[ASDisplayNode detailedLayoutDescription] property to aid debugging. [Adlai Holler](https://github.com/Adlai-Holler) [#476](https://github.com/TextureGroup/Texture/pull/476) - Fix an issue that causes calculatedLayoutDidChange being called needlessly. [Huy Nguyen](https://github.com/nguyenhuy) [#490](https://github.com/TextureGroup/Texture/pull/490) - Negate iOS 11 automatic estimated table row heights. [Christian Selig](https://github.com/christianselig) [#485](https://github.com/TextureGroup/Texture/pull/485) -- Rename ASCellNode.viewModel to ASCellNode.nodeViewModel to reduce collisions with subclass properties implemented by clients. [Adlai Holler](https://github.com/Adlai-Holler) [#499](https://github.com/TextureGroup/Texture/pull/499) +- Rename ASCellNode.viewModel to ASCellNode.nodeModel to reduce collisions with subclass properties implemented by clients. [Adlai Holler](https://github.com/Adlai-Holler) [#504](https://github.com/TextureGroup/Texture/pull/504) - [Breaking] Add content offset bridging property to ASTableNode and ASCollectionNode. Deprecate related methods in ASTableView and ASCollectionView [Huy Nguyen](https://github.com/nguyenhuy) [#460](https://github.com/TextureGroup/Texture/pull/460) ##2.3.5 diff --git a/Source/ASCellNode.h b/Source/ASCellNode.h index bcd5b9ccf..2c911f17a 100644 --- a/Source/ASCellNode.h +++ b/Source/ASCellNode.h @@ -123,14 +123,14 @@ typedef NS_ENUM(NSUInteger, ASCellNodeVisibilityEvent) { * * This property may be set off the main thread, but this method will never be invoked concurrently on the */ -@property (atomic, nullable) id nodeViewModel; +@property (atomic, nullable) id nodeModel; /** - * Asks the node whether it can be updated to the given view model. + * Asks the node whether it can be updated to the given node model. * * The default implementation returns YES if the class matches that of the current view-model. */ -- (BOOL)canUpdateToViewModel:(id)viewModel; +- (BOOL)canUpdateToNodeModel:(id)nodeModel; /** * The backing view controller, or @c nil if the node wasn't initialized with backing view controller diff --git a/Source/ASCellNode.mm b/Source/ASCellNode.mm index 6ff4b7d83..400be0796 100644 --- a/Source/ASCellNode.mm +++ b/Source/ASCellNode.mm @@ -170,9 +170,9 @@ - (void)__setHighlightedFromUIKit:(BOOL)highlighted; } } -- (BOOL)canUpdateToViewModel:(id)viewModel +- (BOOL)canUpdateToNodeModel:(id)nodeModel { - return [self.nodeViewModel class] == [viewModel class]; + return [self.nodeModel class] == [nodeModel class]; } - (NSIndexPath *)indexPath diff --git a/Source/ASCollectionNode.h b/Source/ASCollectionNode.h index 0ca893c2d..9ba6fdcee 100644 --- a/Source/ASCollectionNode.h +++ b/Source/ASCollectionNode.h @@ -433,15 +433,15 @@ NS_ASSUME_NONNULL_BEGIN - (nullable __kindof ASCellNode *)nodeForItemAtIndexPath:(NSIndexPath *)indexPath AS_WARN_UNUSED_RESULT; /** - * Retrieves the view-model for the item at the given index path, if any. + * Retrieves the node-model for the item at the given index path, if any. * * @param indexPath The index path of the requested item. * - * @return The view-model for the given item, or @c nil if no item exists at the specified path or no view-model was provided. + * @return The node-model for the given item, or @c nil if no item exists at the specified path or no node-model was provided. * * @warning This API is beta and subject to change. We'll try to provide an easy migration path. */ -- (nullable id)viewModelForItemAtIndexPath:(NSIndexPath *)indexPath AS_WARN_UNUSED_RESULT; +- (nullable id)nodeModelForItemAtIndexPath:(NSIndexPath *)indexPath AS_WARN_UNUSED_RESULT; /** * Retrieve the index path for the item with the given node. @@ -537,7 +537,7 @@ NS_ASSUME_NONNULL_BEGIN * * @return An object that contains all the data for this item. */ -- (nullable id)collectionNode:(ASCollectionNode *)collectionNode viewModelForItemAtIndexPath:(NSIndexPath *)indexPath; +- (nullable id)collectionNode:(ASCollectionNode *)collectionNode nodeModelForItemAtIndexPath:(NSIndexPath *)indexPath; /** * Similar to -collectionNode:nodeForItemAtIndexPath: diff --git a/Source/ASCollectionNode.mm b/Source/ASCollectionNode.mm index b867a0ea9..994e26188 100644 --- a/Source/ASCollectionNode.mm +++ b/Source/ASCollectionNode.mm @@ -624,10 +624,10 @@ - (ASCellNode *)nodeForItemAtIndexPath:(NSIndexPath *)indexPath return [self.dataController.pendingMap elementForItemAtIndexPath:indexPath].node; } -- (id)viewModelForItemAtIndexPath:(NSIndexPath *)indexPath +- (id)nodeModelForItemAtIndexPath:(NSIndexPath *)indexPath { [self reloadDataInitiallyIfNeeded]; - return [self.dataController.pendingMap elementForItemAtIndexPath:indexPath].viewModel; + return [self.dataController.pendingMap elementForItemAtIndexPath:indexPath].nodeModel; } - (NSIndexPath *)indexPathForNode:(ASCellNode *)cellNode diff --git a/Source/ASCollectionView.mm b/Source/ASCollectionView.mm index da6eadcdc..83bcc2447 100644 --- a/Source/ASCollectionView.mm +++ b/Source/ASCollectionView.mm @@ -202,7 +202,7 @@ @interface ASCollectionView () )asyncDataSource _asyncDataSourceFlags.collectionNodeNodeForSupplementaryElement = [_asyncDataSource respondsToSelector:@selector(collectionNode:nodeForSupplementaryElementOfKind:atIndexPath:)]; _asyncDataSourceFlags.collectionNodeNodeBlockForSupplementaryElement = [_asyncDataSource respondsToSelector:@selector(collectionNode:nodeBlockForSupplementaryElementOfKind:atIndexPath:)]; _asyncDataSourceFlags.collectionNodeSupplementaryElementKindsInSection = [_asyncDataSource respondsToSelector:@selector(collectionNode:supplementaryElementKindsInSection:)]; - _asyncDataSourceFlags.viewModelForItem = [_asyncDataSource respondsToSelector:@selector(collectionNode:viewModelForItemAtIndexPath:)]; + _asyncDataSourceFlags.nodeModelForItem = [_asyncDataSource respondsToSelector:@selector(collectionNode:nodeModelForItemAtIndexPath:)]; _asyncDataSourceFlags.interop = [_asyncDataSource conformsToProtocol:@protocol(ASCollectionDataSourceInterop)]; if (_asyncDataSourceFlags.interop) { @@ -1662,14 +1662,14 @@ - (void)_beginBatchFetching #pragma mark - ASDataControllerSource -- (id)dataController:(ASDataController *)dataController viewModelForItemAtIndexPath:(NSIndexPath *)indexPath +- (id)dataController:(ASDataController *)dataController nodeModelForItemAtIndexPath:(NSIndexPath *)indexPath { - if (!_asyncDataSourceFlags.viewModelForItem) { + if (!_asyncDataSourceFlags.nodeModelForItem) { return nil; } GET_COLLECTIONNODE_OR_RETURN(collectionNode, nil); - return [_asyncDataSource collectionNode:collectionNode viewModelForItemAtIndexPath:indexPath]; + return [_asyncDataSource collectionNode:collectionNode nodeModelForItemAtIndexPath:indexPath]; } - (ASCellNodeBlock)dataController:(ASDataController *)dataController nodeBlockAtIndexPath:(NSIndexPath *)indexPath diff --git a/Source/ASTableView.mm b/Source/ASTableView.mm index 3f230ba40..d0e529c8b 100644 --- a/Source/ASTableView.mm +++ b/Source/ASTableView.mm @@ -1628,7 +1628,7 @@ - (void)rangeController:(ASRangeController *)rangeController updateWithChangeSet #pragma mark - ASDataControllerSource -- (id)dataController:(ASDataController *)dataController viewModelForItemAtIndexPath:(NSIndexPath *)indexPath +- (id)dataController:(ASDataController *)dataController nodeModelForItemAtIndexPath:(NSIndexPath *)indexPath { // Not currently supported for tables. Will be added when the collection API stabilizes. return nil; diff --git a/Source/Details/ASCollectionElement.h b/Source/Details/ASCollectionElement.h index 252d39433..0272aae26 100644 --- a/Source/Details/ASCollectionElement.h +++ b/Source/Details/ASCollectionElement.h @@ -30,9 +30,9 @@ AS_SUBCLASSING_RESTRICTED @property (nonatomic, assign) ASSizeRange constrainedSize; @property (nonatomic, readonly, weak) id owningNode; @property (nonatomic, assign) ASPrimitiveTraitCollection traitCollection; -@property (nonatomic, readonly, nullable) id viewModel; +@property (nonatomic, readonly, nullable) id nodeModel; -- (instancetype)initWithViewModel:(nullable id)viewModel +- (instancetype)initWithNodeModel:(nullable id)nodeModel nodeBlock:(ASCellNodeBlock)nodeBlock supplementaryElementKind:(nullable NSString *)supplementaryElementKind constrainedSize:(ASSizeRange)constrainedSize diff --git a/Source/Details/ASCollectionElement.mm b/Source/Details/ASCollectionElement.mm index 3c16011da..75f75e918 100644 --- a/Source/Details/ASCollectionElement.mm +++ b/Source/Details/ASCollectionElement.mm @@ -31,7 +31,7 @@ @implementation ASCollectionElement { ASCellNode *_node; } -- (instancetype)initWithViewModel:(id)viewModel +- (instancetype)initWithNodeModel:(id)nodeModel nodeBlock:(ASCellNodeBlock)nodeBlock supplementaryElementKind:(NSString *)supplementaryElementKind constrainedSize:(ASSizeRange)constrainedSize @@ -41,7 +41,7 @@ - (instancetype)initWithViewModel:(id)viewModel NSAssert(nodeBlock != nil, @"Node block must not be nil"); self = [super init]; if (self) { - _viewModel = viewModel; + _nodeModel = nodeModel; _nodeBlock = nodeBlock; _supplementaryElementKind = [supplementaryElementKind copy]; _constrainedSize = constrainedSize; @@ -64,7 +64,7 @@ - (ASCellNode *)node node.owningNode = _owningNode; node.collectionElement = self; ASTraitCollectionPropagateDown(node, _traitCollection); - node.nodeViewModel = _viewModel; + node.nodeModel = _nodeModel; _node = node; } return _node; diff --git a/Source/Details/ASDataController.h b/Source/Details/ASDataController.h index 6fd85e89a..82791a685 100644 --- a/Source/Details/ASDataController.h +++ b/Source/Details/ASDataController.h @@ -78,7 +78,7 @@ extern NSString * const ASCollectionInvalidUpdateException; */ - (BOOL)dataController:(ASDataController *)dataController presentedSizeForElement:(ASCollectionElement *)element matchesSize:(CGSize)size; -- (nullable id)dataController:(ASDataController *)dataController viewModelForItemAtIndexPath:(NSIndexPath *)indexPath; +- (nullable id)dataController:(ASDataController *)dataController nodeModelForItemAtIndexPath:(NSIndexPath *)indexPath; @optional diff --git a/Source/Details/ASDataController.mm b/Source/Details/ASDataController.mm index 9e9b9348c..102fca123 100644 --- a/Source/Details/ASDataController.mm +++ b/Source/Details/ASDataController.mm @@ -330,18 +330,18 @@ - (void)_insertElementsIntoMap:(ASMutableElementMap *)map id node = self.node; for (NSIndexPath *indexPath in indexPaths) { ASCellNodeBlock nodeBlock; - id viewModel; + id nodeModel; if (isRowKind) { - viewModel = [dataSource dataController:self viewModelForItemAtIndexPath:indexPath]; + nodeModel = [dataSource dataController:self nodeModelForItemAtIndexPath:indexPath]; // Get the prior element and attempt to update the existing cell node. - if (viewModel != nil && !changeSet.includesReloadData) { + if (nodeModel != nil && !changeSet.includesReloadData) { NSIndexPath *oldIndexPath = [changeSet oldIndexPathForNewIndexPath:indexPath]; if (oldIndexPath != nil) { ASCollectionElement *oldElement = [previousMap elementForItemAtIndexPath:oldIndexPath]; ASCellNode *oldNode = oldElement.node; - if ([oldNode canUpdateToViewModel:viewModel]) { - // Just wrap the node in a block. The collection element will -setViewModel: + if ([oldNode canUpdateToNodeModel:nodeModel]) { + // Just wrap the node in a block. The collection element will -setNodeModel: nodeBlock = ^{ return oldNode; }; @@ -360,7 +360,7 @@ - (void)_insertElementsIntoMap:(ASMutableElementMap *)map constrainedSize = [self constrainedSizeForNodeOfKind:kind atIndexPath:indexPath]; } - ASCollectionElement *element = [[ASCollectionElement alloc] initWithViewModel:viewModel + ASCollectionElement *element = [[ASCollectionElement alloc] initWithNodeModel:nodeModel nodeBlock:nodeBlock supplementaryElementKind:isRowKind ? nil : kind constrainedSize:constrainedSize diff --git a/Tests/ASCollectionModernDataSourceTests.m b/Tests/ASCollectionModernDataSourceTests.m index 5fd096f19..a6daa9782 100644 --- a/Tests/ASCollectionModernDataSourceTests.m +++ b/Tests/ASCollectionModernDataSourceTests.m @@ -24,7 +24,7 @@ @interface ASTestCellNode : ASCellNode @end @interface ASTestSection : NSObject -@property (nonatomic, readonly) NSMutableArray *viewModels; +@property (nonatomic, readonly) NSMutableArray *nodeModels; @end @implementation ASCollectionModernDataSourceTests { @@ -41,10 +41,10 @@ - (void)setUp { // Default is 2 sections: 2 items in first, 1 item in second. sections = [NSMutableArray array]; [sections addObject:[ASTestSection new]]; - [sections[0].viewModels addObject:[NSObject new]]; - [sections[0].viewModels addObject:[NSObject new]]; + [sections[0].nodeModels addObject:[NSObject new]]; + [sections[0].nodeModels addObject:[NSObject new]]; [sections addObject:[ASTestSection new]]; - [sections[1].viewModels addObject:[NSObject new]]; + [sections[1].nodeModels addObject:[NSObject new]]; window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]; viewController = [[UIViewController alloc] init]; @@ -60,7 +60,7 @@ - (void)setUp { @selector(numberOfSectionsInCollectionNode:), @selector(collectionNode:numberOfItemsInSection:), @selector(collectionNode:nodeBlockForItemAtIndexPath:), - @selector(collectionNode:viewModelForItemAtIndexPath:), + @selector(collectionNode:nodeModelForItemAtIndexPath:), @selector(collectionNode:contextForSection:), nil]; [mockDataSource setExpectationOrderMatters:YES]; @@ -112,7 +112,7 @@ - (void)testInsertingAnItem skippedReloadIndexPaths:nil]; } -- (void)testReloadingAnItemWithACompatibleViewModel +- (void)testReloadingAnItemWithACompatibleNodeModel { [self loadInitialData]; @@ -120,15 +120,15 @@ - (void)testReloadingAnItemWithACompatibleViewModel NSIndexPath *reloadedPath = [NSIndexPath indexPathForItem:1 inSection:0]; NSIndexPath *deletedPath = [NSIndexPath indexPathForItem:0 inSection:0]; - id viewModel = [NSObject new]; + id nodeModel = [NSObject new]; - // Cell node should get -canUpdateToViewModel: + // Cell node should get -canUpdateToNodeModel: id mockCellNode = [collectionNode nodeForItemAtIndexPath:reloadedPath]; - OCMExpect([mockCellNode canUpdateToViewModel:viewModel]) + OCMExpect([mockCellNode canUpdateToNodeModel:nodeModel]) .andReturn(YES); [self performUpdateReloadingSections:nil - reloadingItems:@{ reloadedPath: viewModel } + reloadingItems:@{ reloadedPath: nodeModel } reloadMappings:@{ reloadedPath: [NSIndexPath indexPathForItem:0 inSection:0] } insertingItems:nil deletingItems:@[ deletedPath ] @@ -168,12 +168,12 @@ - (void)loadInitialData // It reads the contents for each item. for (NSInteger section = 0; section < sections.count; section++) { - NSArray *viewModels = sections[section].viewModels; + NSArray *nodeModels = sections[section].nodeModels; // For each item: - for (NSInteger i = 0; i < viewModels.count; i++) { + for (NSInteger i = 0; i < nodeModels.count; i++) { NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:section]; - [self expectViewModelMethodForItemAtIndexPath:indexPath viewModel:viewModels[i]]; + [self expectNodeModelMethodForItemAtIndexPath:indexPath nodeModel:nodeModels[i]]; [self expectNodeBlockMethodForItemAtIndexPath:indexPath]; } } @@ -201,14 +201,14 @@ - (void)expectDataSourceCountMethods // Note: Skip fast enumeration for readability. for (NSInteger section = 0; section < sections.count; section++) { OCMExpect([mockDataSource collectionNode:collectionNode numberOfItemsInSection:section]) - .andReturn(sections[section].viewModels.count); + .andReturn(sections[section].nodeModels.count); } } -- (void)expectViewModelMethodForItemAtIndexPath:(NSIndexPath *)indexPath viewModel:(id)viewModel +- (void)expectNodeModelMethodForItemAtIndexPath:(NSIndexPath *)indexPath nodeModel:(id)nodeModel { - OCMExpect([mockDataSource collectionNode:collectionNode viewModelForItemAtIndexPath:indexPath]) - .andReturn(viewModel); + OCMExpect([mockDataSource collectionNode:collectionNode nodeModelForItemAtIndexPath:indexPath]) + .andReturn(nodeModel); } - (void)expectContextMethodForSection:(NSInteger)section @@ -240,21 +240,21 @@ - (void)assertCollectionNodeContent for (NSInteger section = 0; section < sections.count; section++) { ASTestSection *sectionObject = sections[section]; - NSArray *viewModels = sectionObject.viewModels; + NSArray *nodeModels = sectionObject.nodeModels; // Assert section object XCTAssertEqualObjects([collectionNode contextForSection:section], sectionObject); // Assert item count - XCTAssertEqual([collectionNode numberOfItemsInSection:section], viewModels.count); - for (NSInteger item = 0; item < viewModels.count; item++) { - // Assert view model + XCTAssertEqual([collectionNode numberOfItemsInSection:section], nodeModels.count); + for (NSInteger item = 0; item < nodeModels.count; item++) { + // Assert node model // Could use pointer equality but the error message is less readable. NSIndexPath *indexPath = [NSIndexPath indexPathForItem:item inSection:section]; - id viewModel = viewModels[indexPath.item]; - XCTAssertEqualObjects(viewModel, [collectionNode viewModelForItemAtIndexPath:indexPath]); + id nodeModel = nodeModels[indexPath.item]; + XCTAssertEqualObjects(nodeModel, [collectionNode nodeModelForItemAtIndexPath:indexPath]); ASCellNode *node = [collectionNode nodeForItemAtIndexPath:indexPath]; - XCTAssertEqualObjects(node.nodeViewModel, viewModel); + XCTAssertEqualObjects(node.nodeModel, nodeModel); } } } @@ -263,7 +263,7 @@ - (void)assertCollectionNodeContent * Updates the collection node, with expectations and assertions about the call-order and the correctness of the * new data. You should update the data source _before_ calling this method. * - * skippedReloadIndexPaths are the old index paths for nodes that should use -canUpdateToViewModel: instead of being refetched. + * skippedReloadIndexPaths are the old index paths for nodes that should use -canUpdateToNodeModel: instead of being refetched. */ - (void)performUpdateReloadingSections:(NSDictionary *)reloadedSections reloadingItems:(NSDictionary *)reloadedItems @@ -275,7 +275,7 @@ - (void)performUpdateReloadingSections:(NSDictionary *)reloadedS [collectionNode performBatchUpdates:^{ // First update our data source. [reloadedItems enumerateKeysAndObjectsUsingBlock:^(NSIndexPath * _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { - sections[key.section].viewModels[key.item] = obj; + sections[key.section].nodeModels[key.item] = obj; }]; [reloadedSections enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { sections[key.integerValue] = obj; @@ -283,13 +283,13 @@ - (void)performUpdateReloadingSections:(NSDictionary *)reloadedS // Deletion paths, sorted descending for (NSIndexPath *indexPath in [deletedItems sortedArrayUsingSelector:@selector(compare:)].reverseObjectEnumerator) { - [sections[indexPath.section].viewModels removeObjectAtIndex:indexPath.item]; + [sections[indexPath.section].nodeModels removeObjectAtIndex:indexPath.item]; } // Insertion paths, sorted ascending. NSArray *insertionsSortedAcending = [insertedItems.allKeys sortedArrayUsingSelector:@selector(compare:)]; for (NSIndexPath *indexPath in insertionsSortedAcending) { - [sections[indexPath.section].viewModels insertObject:insertedItems[indexPath] atIndex:indexPath.item]; + [sections[indexPath.section].nodeModels insertObject:insertedItems[indexPath] atIndex:indexPath.item]; } // Then update the collection node. @@ -314,10 +314,10 @@ - (void)performUpdateReloadingSections:(NSDictionary *)reloadedS // Go through reloaded sections and add all their items into `insertsPlusReloads` [reloadedSectionIndexes enumerateIndexesUsingBlock:^(NSUInteger section, BOOL * _Nonnull stop) { [self expectContextMethodForSection:section]; - NSArray *viewModels = sections[section].viewModels; - for (NSInteger i = 0; i < viewModels.count; i++) { + NSArray *nodeModels = sections[section].nodeModels; + for (NSInteger i = 0; i < nodeModels.count; i++) { NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:section]; - insertsPlusReloads[indexPath] = viewModels[i]; + insertsPlusReloads[indexPath] = nodeModels[i]; } }]; @@ -326,7 +326,7 @@ - (void)performUpdateReloadingSections:(NSDictionary *)reloadedS }]; for (NSIndexPath *indexPath in [insertsPlusReloads.allKeys sortedArrayUsingSelector:@selector(compare:)]) { - [self expectViewModelMethodForItemAtIndexPath:indexPath viewModel:insertsPlusReloads[indexPath]]; + [self expectNodeModelMethodForItemAtIndexPath:indexPath nodeModel:insertsPlusReloads[indexPath]]; NSIndexPath *oldIndexPath = [reloadMappings allKeysForObject:indexPath].firstObject; BOOL isSkippedReload = oldIndexPath && [skippedReloadIndexPaths containsObject:oldIndexPath]; if (!isSkippedReload) { @@ -335,7 +335,7 @@ - (void)performUpdateReloadingSections:(NSDictionary *)reloadedS } } completion:nil]; - // Assert that the counts and view models are all correct now. + // Assert that the counts and node models are all correct now. [self assertCollectionNodeContent]; } @@ -345,9 +345,9 @@ - (void)performUpdateReloadingSections:(NSDictionary *)reloadedS @implementation ASTestCellNode -- (BOOL)canUpdateToViewModel:(id)viewModel +- (BOOL)canUpdateToNodeModel:(id)nodeModel { - // Our tests default to NO for migrating view models. We use OCMExpect to return YES when we specifically want to. + // Our tests default to NO for migrating node models. We use OCMExpect to return YES when we specifically want to. return NO; } @@ -360,7 +360,7 @@ @implementation ASTestSection - (instancetype)init { if (self = [super init]) { - _viewModels = [NSMutableArray array]; + _nodeModels = [NSMutableArray array]; } return self; } From 6b3e2ba4e0f64053b4e9b594f4016c3a1e4f43a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ka=C5=A1par?= Date: Sat, 12 Aug 2017 08:03:42 -0700 Subject: [PATCH 3/5] [ASCoreAnimationExtras] Update documentation for resizbale images #trivial (#492) * Update documentation for resizbale images * Add documentation to ASDisplayNodeSetResizableContents --- Source/Private/_ASCoreAnimationExtras.h | 7 ++++++- Source/Private/_ASCoreAnimationExtras.mm | 10 +++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Source/Private/_ASCoreAnimationExtras.h b/Source/Private/_ASCoreAnimationExtras.h index 327254917..69c305395 100644 --- a/Source/Private/_ASCoreAnimationExtras.h +++ b/Source/Private/_ASCoreAnimationExtras.h @@ -38,7 +38,12 @@ ASDISPLAYNODE_EXTERN_C_BEGIN @interface ASDisplayNode (ASResizableContents) @end -// This function can operate on either an ASDisplayNode (including un-loaded) or CALayer directly. +/** + This function can operate on either an ASDisplayNode (including un-loaded) or CALayer directly. More info about resizing mode: https://github.com/TextureGroup/Texture/issues/439 + + @param obj ASDisplayNode, CALayer or object that conforms to `ASResizableContents` protocol + @param image Image you would like to resize + */ extern void ASDisplayNodeSetResizableContents(id obj, UIImage *image); /** diff --git a/Source/Private/_ASCoreAnimationExtras.mm b/Source/Private/_ASCoreAnimationExtras.mm index 3cd18c8e8..65172962e 100644 --- a/Source/Private/_ASCoreAnimationExtras.mm +++ b/Source/Private/_ASCoreAnimationExtras.mm @@ -26,20 +26,16 @@ extern void ASDisplayNodeSetupLayerContentsWithResizableImage(CALayer *layer, UI extern void ASDisplayNodeSetResizableContents(id obj, UIImage *image) { - // FIXME: This method does not currently handle UIImageResizingModeTile, which is the default on iOS 6. - // I'm not sure of a way to use CALayer directly to perform such tiling on the GPU, though the stretch is handled by the GPU, - // and CALayer.h documents the fact that contentsCenter is used to stretch the pixels. - if (image) { + ASDisplayNodeCAssert(image.resizingMode == UIImageResizingModeStretch || UIEdgeInsetsEqualToEdgeInsets(image.capInsets, UIEdgeInsetsZero), + @"Image insets must be all-zero or resizingMode has to be UIImageResizingModeStretch. XCode assets default value is UIImageResizingModeTile which is not supported by Texture because of GPU-accelerated CALayer features."); + // Image may not actually be stretchable in one or both dimensions; this is handled obj.contents = (id)[image CGImage]; obj.contentsScale = [image scale]; obj.rasterizationScale = [image scale]; CGSize imageSize = [image size]; - ASDisplayNodeCAssert(image.resizingMode == UIImageResizingModeStretch || UIEdgeInsetsEqualToEdgeInsets(image.capInsets, UIEdgeInsetsZero), - @"the resizing mode of image should be stretch; if not, then its insets must be all-zero"); - UIEdgeInsets insets = [image capInsets]; // These are lifted from what UIImageView does by experimentation. Without these exact values, the stretching is slightly off. From a929950d2c071e13574af3f2b9195855b0784c3e Mon Sep 17 00:00:00 2001 From: Max Wang Date: Mon, 14 Aug 2017 08:31:52 -0700 Subject: [PATCH 4/5] Fix SIMULATE_WEB_RESPONSE not imported (#450) * fix SIMULATE_WEB_RESPONSE not imported (Reported in #449). * changes per review * Update license of ViewController.m --- examples/ASCollectionView/Sample/ViewController.m | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/ASCollectionView/Sample/ViewController.m b/examples/ASCollectionView/Sample/ViewController.m index b895e9c9b..3d945929d 100644 --- a/examples/ASCollectionView/Sample/ViewController.m +++ b/examples/ASCollectionView/Sample/ViewController.m @@ -16,7 +16,7 @@ // #import "ViewController.h" - +#import "AppDelegate.h" #import #import "SupplementaryNode.h" #import "ItemNode.h" @@ -82,18 +82,18 @@ - (void)viewDidLoad { NSLog(@"ViewController is not nil"); strongSelf->_data = [[NSArray alloc] init]; - [strongSelf->_collectionView performBatchUpdates:^{ - [strongSelf->_collectionView insertSections:[[NSIndexSet alloc] initWithIndexesInRange:NSMakeRange(0, 100)]]; + [strongSelf->_collectionNode performBatchUpdates:^{ + [strongSelf->_collectionNode insertSections:[[NSIndexSet alloc] initWithIndexesInRange:NSMakeRange(0, 100)]]; } completion:nil]; - NSLog(@"ViewController finished updating collectionView"); + NSLog(@"ViewController finished updating collectionNode"); } else { - NSLog(@"ViewController is nil - won't update collectionView"); + NSLog(@"ViewController is nil - won't update collectionNode"); } }; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), mockWebService); - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(4 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [self.navigationController popViewControllerAnimated:YES]; }); #endif From afeb25a6b4dd1f4fa147e809927e89aa3aa50d8e Mon Sep 17 00:00:00 2001 From: Huy Nguyen Date: Mon, 14 Aug 2017 16:52:45 +0100 Subject: [PATCH 5/5] [examples/ASCollectionView] Register supplementary kinds (#508) --- examples/ASCollectionView/Sample/ViewController.m | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/ASCollectionView/Sample/ViewController.m b/examples/ASCollectionView/Sample/ViewController.m index 3d945929d..fa093f80a 100644 --- a/examples/ASCollectionView/Sample/ViewController.m +++ b/examples/ASCollectionView/Sample/ViewController.m @@ -55,6 +55,8 @@ - (void)viewDidLoad layout.headerReferenceSize = CGSizeMake(50.0, 50.0); layout.footerReferenceSize = CGSizeMake(50.0, 50.0); self.collectionNode = [[ASCollectionNode alloc] initWithFrame:self.view.bounds collectionViewLayout:layout]; + [self.collectionNode registerSupplementaryNodeOfKind:UICollectionElementKindSectionHeader]; + [self.collectionNode registerSupplementaryNodeOfKind:UICollectionElementKindSectionFooter]; #endif self.collectionNode.dataSource = self;