From 929d118c962dcf595386daf5c91ce30e1f8e577d Mon Sep 17 00:00:00 2001 From: Max Wang Date: Sun, 16 Jul 2017 16:59:28 -0700 Subject: [PATCH 1/3] fix SIMULATE_WEB_RESPONSE not imported #449 --- examples/ASCollectionView/Sample/ViewController.m | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/ASCollectionView/Sample/ViewController.m b/examples/ASCollectionView/Sample/ViewController.m index d00ea60df..4e6a04e97 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" @@ -70,8 +70,8 @@ - (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"); } @@ -81,7 +81,7 @@ - (void)viewDidLoad }; 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 329f35ff56aa6605ba9157174568cfd18a7a5373 Mon Sep 17 00:00:00 2001 From: Max Wang Date: Mon, 5 Feb 2018 14:10:21 -0800 Subject: [PATCH 2/3] Fix to make rangeMode update in right time --- Source/ASCollectionView.mm | 1 + Source/ASTableView.mm | 1 + Source/Details/ASRangeController.h | 5 +++++ Source/Details/ASRangeController.mm | 14 ++++++++++---- Tests/ASCollectionViewTests.mm | 1 + 5 files changed, 18 insertions(+), 4 deletions(-) diff --git a/Source/ASCollectionView.mm b/Source/ASCollectionView.mm index 0c706faa4..7c20dbddf 100644 --- a/Source/ASCollectionView.mm +++ b/Source/ASCollectionView.mm @@ -1511,6 +1511,7 @@ - (void)scrollViewDidScroll:(UIScrollView *)scrollView // If a scroll happenes the current range mode needs to go to full ASInterfaceState interfaceState = [self interfaceStateForRangeController:_rangeController]; if (ASInterfaceStateIncludesVisible(interfaceState)) { + _rangeController.contentOffsetHasChanged = YES; [_rangeController updateCurrentRangeWithMode:ASLayoutRangeModeFull]; [self _checkForBatchFetching]; } diff --git a/Source/ASTableView.mm b/Source/ASTableView.mm index 4606726f2..7bcd0fd5c 100644 --- a/Source/ASTableView.mm +++ b/Source/ASTableView.mm @@ -1218,6 +1218,7 @@ - (void)scrollViewDidScroll:(UIScrollView *)scrollView // If a scroll happenes the current range mode needs to go to full ASInterfaceState interfaceState = [self interfaceStateForRangeController:_rangeController]; if (ASInterfaceStateIncludesVisible(interfaceState)) { + _rangeController.contentOffsetHasChanged = YES; [_rangeController updateCurrentRangeWithMode:ASLayoutRangeModeFull]; [self _checkForBatchFetching]; } diff --git a/Source/Details/ASRangeController.h b/Source/Details/ASRangeController.h index 46a5cbf69..152c4e8b5 100644 --- a/Source/Details/ASRangeController.h +++ b/Source/Details/ASRangeController.h @@ -100,6 +100,11 @@ AS_SUBCLASSING_RESTRICTED */ @property (nonatomic, weak) id delegate; +/** + * Property that indicates whether the scroll view for this range controller has ever changed its contentOffset. + */ +@property (nonatomic, assign) BOOL contentOffsetHasChanged; + @end diff --git a/Source/Details/ASRangeController.mm b/Source/Details/ASRangeController.mm index 818fb3a1d..4d10838b7 100644 --- a/Source/Details/ASRangeController.mm +++ b/Source/Details/ASRangeController.mm @@ -45,6 +45,7 @@ @interface ASRangeController () NSSet *_allPreviousIndexPaths; NSHashTable *_visibleNodes; ASLayoutRangeMode _currentRangeMode; + BOOL _contentOffsetHasChanged; BOOL _preserveCurrentRangeMode; BOOL _didRegisterForNodeDisplayNotifications; CFTimeInterval _pendingDisplayNodesTimestamp; @@ -77,6 +78,7 @@ - (instancetype)init _rangeIsValid = YES; _currentRangeMode = ASLayoutRangeModeUnspecified; + _contentOffsetHasChanged = NO; _preserveCurrentRangeMode = NO; _previousScrollDirection = ASScrollDirectionDown | ASScrollDirectionRight; @@ -237,9 +239,13 @@ - (void)_updateVisibleNodeIndexPaths ASInterfaceState selfInterfaceState = [self interfaceState]; ASLayoutRangeMode rangeMode = _currentRangeMode; - // If the range mode is explicitly set via updateCurrentRangeWithMode: it will last in that mode until the - // range controller becomes visible again or explicitly changes the range mode again - if ((!_preserveCurrentRangeMode && ASInterfaceStateIncludesVisible(selfInterfaceState)) || [[self class] isFirstRangeUpdateForRangeMode:rangeMode]) { + BOOL updateRangeMode = !_preserveCurrentRangeMode && _contentOffsetHasChanged; + + // If we've never scrolled before, we never update the range mode, so it doesn't jump into Full too early. + // This can happen if we have multiple, noisy updates occurring from application code before the user has engaged. + // If the range mode is explicitly set via updateCurrentRangeWithMode:, we'll preserve that for at least one update cycle. + // Once the user has scrolled and the range is visible, we'll always resume managing the range mode automatically. + if ((updateRangeMode && ASInterfaceStateIncludesVisible(selfInterfaceState)) || [[self class] isFirstRangeUpdateForRangeMode:rangeMode]) { rangeMode = [ASRangeController rangeModeForInterfaceState:selfInterfaceState currentRangeMode:_currentRangeMode]; } @@ -412,7 +418,7 @@ - (void)_updateVisibleNodeIndexPaths // NSLog(@"custom: %@", visibleNodePathsSet); // } [modifiedIndexPaths sortUsingSelector:@selector(compare:)]; - NSLog(@"Range update complete; modifiedIndexPaths: %@", [self descriptionWithIndexPaths:modifiedIndexPaths]); + NSLog(@"Range update complete; modifiedIndexPaths: %@, rangeMode: %d", [self descriptionWithIndexPaths:modifiedIndexPaths], rangeMode); #endif ASSignpostEnd(ASSignpostRangeControllerUpdate); diff --git a/Tests/ASCollectionViewTests.mm b/Tests/ASCollectionViewTests.mm index b223e246f..11ab711d6 100644 --- a/Tests/ASCollectionViewTests.mm +++ b/Tests/ASCollectionViewTests.mm @@ -1071,6 +1071,7 @@ - (void)testInitialRangeBounds for (NSInteger i = 0; i < c; i++) { NSIndexPath *ip = [NSIndexPath indexPathForItem:i inSection:s]; ASCellNode *node = [cn nodeForItemAtIndexPath:ip]; + [[NSRunLoop mainRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.001]]; if (node.inPreloadState) { CGRect frame = [cn.view layoutAttributesForItemAtIndexPath:ip].frame; r = CGRectUnion(r, frame); From 74b9b09aaa761fd653f2dcbf5f58f2fde054485b Mon Sep 17 00:00:00 2001 From: Max Wang Date: Tue, 6 Feb 2018 17:53:13 -0800 Subject: [PATCH 3/3] Keep collection/table node alive if view still in use. --- Source/ASCollectionNode.mm | 7 +++++++ Source/ASCollectionView.mm | 21 ++++++++++++++++++++- Source/ASTableNode.mm | 7 +++++++ Source/ASTableView.mm | 21 ++++++++++++++++++++- 4 files changed, 54 insertions(+), 2 deletions(-) diff --git a/Source/ASCollectionNode.mm b/Source/ASCollectionNode.mm index 2449377fd..01669ca79 100644 --- a/Source/ASCollectionNode.mm +++ b/Source/ASCollectionNode.mm @@ -172,6 +172,13 @@ - (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionVi return self; } +- (void)dealloc +{ + if ([self isNodeLoaded]) { + ASDisplayNodeAssert(self.view.superview == nil, @"Node's view should be removed from hierarchy."); + } +} + #pragma mark ASDisplayNode - (void)didLoad diff --git a/Source/ASCollectionView.mm b/Source/ASCollectionView.mm index 99e32c26e..9727ce704 100644 --- a/Source/ASCollectionView.mm +++ b/Source/ASCollectionView.mm @@ -151,7 +151,12 @@ @interface ASCollectionView ()