diff --git a/CHANGELOG.md b/CHANGELOG.md index 456567919..e23451c2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## master * Add your own contributions to the next release on the line below this with your name. +- [ASCollectionNode] Add -isProcessingUpdates and -onDidFinishProcessingUpdates: APIs. [#522](https://github.com/TextureGroup/Texture/pull/522) [Scott Goodson](https://github.com/appleguy) - [Accessibility] Add .isAccessibilityContainer property, allowing automatic aggregation of children's a11y labels. [#468][Scott Goodson](https://github.com/appleguy) - [ASImageNode] Enabled .clipsToBounds by default, fixing the use of .cornerRadius and clipping of GIFs. [Scott Goodson](https://github.com/appleguy) [#466](https://github.com/TextureGroup/Texture/pull/466) - Fix an issue in layout transition that causes it to unexpectedly use the old layout [Huy Nguyen](https://github.com/nguyenhuy) [#464](https://github.com/TextureGroup/Texture/pull/464) diff --git a/Source/ASCollectionNode.h b/Source/ASCollectionNode.h index 9ba6fdcee..352867e9f 100644 --- a/Source/ASCollectionNode.h +++ b/Source/ASCollectionNode.h @@ -252,10 +252,39 @@ NS_ASSUME_NONNULL_BEGIN */ - (void)performBatchUpdates:(nullable AS_NOESCAPE void (^)())updates completion:(nullable void (^)(BOOL finished))completion; +/** + * Returns YES if the ASCollectionNode is still processing changes from performBatchUpdates:. + * This is typically the concurrent allocation (calling nodeBlocks) and layout of newly inserted + * ASCellNodes. If YES is returned, then calling -waitUntilAllUpdatesAreProcessed may take tens of + * milliseconds to return as it blocks on these concurrent operations. + * + * Returns NO if ASCollectionNode is fully synchronized with the underlying UICollectionView. This + * means that until the next performBatchUpdates: is called, it is safe to compare UIKit values + * (such as from UICollectionViewLayout) with your app's data source. + * + * This method will always return NO if called immediately after -waitUntilAllUpdatesAreProcessed. + */ +@property (nonatomic, readonly) BOOL isProcessingUpdates; + +/** + * Schedules a block to be performed (on the main thread) after processing of performBatchUpdates: + * is finished (completely synchronized to UIKit). The blocks will be run at the moment that + * -isProcessingUpdates changes from YES to NO; + * + * When isProcessingUpdates == NO, the block is run block immediately (before the method returns). + * + * Blocks scheduled by this mechanism are NOT guaranteed to run in the order they are scheduled. + * They may also be delayed if performBatchUpdates continues to be called; the blocks will wait until + * all running updates are finished. + * + * Calling -waitUntilAllUpdatesAreProcessed is one way to flush any pending update completion blocks. + */ +- (void)onDidFinishProcessingUpdates:(nullable void (^)())didFinishProcessingUpdates; + /** * Blocks execution of the main thread until all section and item updates are committed to the view. This method must be called from the main thread. */ -- (void)waitUntilAllUpdatesAreCommitted; +- (void)waitUntilAllUpdatesAreProcessed; /** * Inserts one or more sections. @@ -501,9 +530,11 @@ NS_ASSUME_NONNULL_BEGIN * @warning This method is substantially more expensive than UICollectionView's version. * * @deprecated This method is deprecated in 2.0. Use @c reloadDataWithCompletion: and - * then @c waitUntilAllUpdatesAreCommitted instead. + * then @c waitUntilAllUpdatesAreProcessed instead. */ -- (void)reloadDataImmediately ASDISPLAYNODE_DEPRECATED_MSG("Use -reloadData / -reloadDataWithCompletion: followed by -waitUntilAllUpdatesAreCommitted instead."); +- (void)reloadDataImmediately ASDISPLAYNODE_DEPRECATED_MSG("Use -reloadData / -reloadDataWithCompletion: followed by -waitUntilAllUpdatesAreProcessed instead."); + +- (void)waitUntilAllUpdatesAreCommitted ASDISPLAYNODE_DEPRECATED_MSG("This method has been renamed to -waitUntilAllUpdatesAreProcessed."); @end diff --git a/Source/ASCollectionNode.mm b/Source/ASCollectionNode.mm index 994e26188..5bb12befd 100644 --- a/Source/ASCollectionNode.mm +++ b/Source/ASCollectionNode.mm @@ -705,7 +705,21 @@ - (void)performBatchUpdates:(void (^)())updates completion:(void (^)(BOOL))compl [self performBatchAnimated:UIView.areAnimationsEnabled updates:updates completion:completion]; } -- (void)waitUntilAllUpdatesAreCommitted +- (BOOL)isProcessingUpdates +{ + return (self.nodeLoaded ? [self.view isProcessingUpdates] : NO); +} + +- (void)onDidFinishProcessingUpdates:(nullable void (^)())completion +{ + if (!self.nodeLoaded) { + completion(); + } else { + [self.view onDidFinishProcessingUpdates:completion]; + } +} + +- (void)waitUntilAllUpdatesAreProcessed { ASDisplayNodeAssertMainThread(); if (self.nodeLoaded) { @@ -713,6 +727,11 @@ - (void)waitUntilAllUpdatesAreCommitted } } +- (void)waitUntilAllUpdatesAreCommitted +{ + [self waitUntilAllUpdatesAreProcessed]; +} + - (void)reloadDataWithCompletion:(void (^)())completion { ASDisplayNodeAssertMainThread(); @@ -738,7 +757,7 @@ - (void)reloadDataImmediately { ASDisplayNodeAssertMainThread(); [self reloadData]; - [self waitUntilAllUpdatesAreCommitted]; + [self waitUntilAllUpdatesAreProcessed]; } - (void)relayoutItems diff --git a/Source/ASCollectionView.h b/Source/ASCollectionView.h index f4dd89138..2a1eb1856 100644 --- a/Source/ASCollectionView.h +++ b/Source/ASCollectionView.h @@ -296,9 +296,11 @@ NS_ASSUME_NONNULL_BEGIN - (void)relayoutItems ASDISPLAYNODE_DEPRECATED_MSG("Use ASCollectionNode method instead."); /** - * Blocks execution of the main thread until all section and row updates are committed. This method must be called from the main thread. + * See ASCollectionNode.h for full documentation of these methods. */ -- (void)waitUntilAllUpdatesAreCommitted ASDISPLAYNODE_DEPRECATED_MSG("Use ASCollectionNode method instead."); +@property (nonatomic, readonly) BOOL isProcessingUpdates; +- (void)onDidFinishProcessingUpdates:(nullable void (^)())completion; +- (void)waitUntilAllUpdatesAreCommitted ASDISPLAYNODE_DEPRECATED_MSG("Use -[ASCollectionNode waitUntilAllUpdatesAreProcessed] instead."); /** * Registers the given kind of supplementary node for use in creating node-backed supplementary views. diff --git a/Source/ASCollectionView.mm b/Source/ASCollectionView.mm index 83bcc2447..e9ed6833b 100644 --- a/Source/ASCollectionView.mm +++ b/Source/ASCollectionView.mm @@ -359,6 +359,16 @@ - (void)relayoutItems [_dataController relayoutAllNodes]; } +- (BOOL)isProcessingUpdates +{ + return [_dataController isProcessingUpdates]; +} + +- (void)onDidFinishProcessingUpdates:(nullable void (^)())completion +{ + [_dataController onDidFinishProcessingUpdates:completion]; +} + - (void)waitUntilAllUpdatesAreCommitted { ASDisplayNodeAssertMainThread(); @@ -367,8 +377,8 @@ - (void)waitUntilAllUpdatesAreCommitted // ASDisplayNodeFailAssert(@"Should not call %@ during batch update", NSStringFromSelector(_cmd)); return; } - - [_dataController waitUntilAllUpdatesAreCommitted]; + + [_dataController waitUntilAllUpdatesAreProcessed]; } - (void)setDataSource:(id)dataSource @@ -2197,7 +2207,7 @@ - (void)layer:(CALayer *)layer didChangeBoundsWithOldValue:(CGRect)oldBounds new if (changedInNonScrollingDirection) { [_dataController relayoutAllNodes]; - [_dataController waitUntilAllUpdatesAreCommitted]; + [_dataController waitUntilAllUpdatesAreProcessed]; // We need to ensure the size requery is done before we update our layout. [self.collectionViewLayout invalidateLayout]; } diff --git a/Source/ASTableNode.h b/Source/ASTableNode.h index 20d59d2e3..08b26a6fd 100644 --- a/Source/ASTableNode.h +++ b/Source/ASTableNode.h @@ -207,9 +207,38 @@ NS_ASSUME_NONNULL_BEGIN - (void)performBatchUpdates:(nullable AS_NOESCAPE void (^)())updates completion:(nullable void (^)(BOOL finished))completion; /** - * Blocks execution of the main thread until all section and row updates are committed. This method must be called from the main thread. + * Returns YES if the ASCollectionNode is still processing changes from performBatchUpdates:. + * This is typically the concurrent allocation (calling nodeBlocks) and layout of newly inserted + * ASCellNodes. If YES is returned, then calling -waitUntilAllUpdatesAreProcessed may take tens of + * milliseconds to return as it blocks on these concurrent operations. + * + * Returns NO if ASCollectionNode is fully synchronized with the underlying UICollectionView. This + * means that until the next performBatchUpdates: is called, it is safe to compare UIKit values + * (such as from UICollectionViewLayout) with your app's data source. + * + * This method will always return NO if called immediately after -waitUntilAllUpdatesAreProcessed. + */ +@property (nonatomic, readonly) BOOL isProcessingUpdates; + +/** + * Schedules a block to be performed (on the main thread) after processing of performBatchUpdates: + * is finished (completely synchronized to UIKit). The blocks will be run at the moment that + * -isProcessingUpdates changes from YES to NO; + * + * When isProcessingUpdates == NO, the block is run block immediately (before the method returns). + * + * Blocks scheduled by this mechanism are NOT guaranteed to run in the order they are scheduled. + * They may also be delayed if performBatchUpdates continues to be called; the blocks will wait until + * all running updates are finished. + * + * Calling -waitUntilAllUpdatesAreProcessed is one way to flush any pending update completion blocks. */ -- (void)waitUntilAllUpdatesAreCommitted; +- (void)onDidFinishProcessingUpdates:(nullable void (^)())didFinishProcessingUpdates; + +/** + * Blocks execution of the main thread until all section and item updates are committed to the view. This method must be called from the main thread. + */ +- (void)waitUntilAllUpdatesAreProcessed; /** * Inserts one or more sections, with an option to animate the insertion. @@ -699,4 +728,10 @@ NS_ASSUME_NONNULL_BEGIN @end +@interface ASTableNode (Deprecated) + +- (void)waitUntilAllUpdatesAreCommitted ASDISPLAYNODE_DEPRECATED_MSG("This method has been renamed to -waitUntilAllUpdatesAreProcessed."); + +@end + NS_ASSUME_NONNULL_END diff --git a/Source/ASTableNode.mm b/Source/ASTableNode.mm index 4cd7fd923..b4a3e06db 100644 --- a/Source/ASTableNode.mm +++ b/Source/ASTableNode.mm @@ -733,7 +733,21 @@ - (void)moveRowAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)n } } -- (void)waitUntilAllUpdatesAreCommitted +- (BOOL)isProcessingUpdates +{ + return (self.nodeLoaded ? [self.view isProcessingUpdates] : NO); +} + +- (void)onDidFinishProcessingUpdates:(nullable void (^)())completion +{ + if (!self.nodeLoaded) { + completion(); + } else { + [self.view onDidFinishProcessingUpdates:completion]; + } +} + +- (void)waitUntilAllUpdatesAreProcessed { ASDisplayNodeAssertMainThread(); if (self.nodeLoaded) { @@ -741,6 +755,11 @@ - (void)waitUntilAllUpdatesAreCommitted } } +- (void)waitUntilAllUpdatesAreCommitted +{ + [self waitUntilAllUpdatesAreProcessed]; +} + #pragma mark - Debugging (Private) - (NSMutableArray *)propertiesForDebugDescription diff --git a/Source/ASTableView.h b/Source/ASTableView.h index 5877ab4d6..0a3d07ec4 100644 --- a/Source/ASTableView.h +++ b/Source/ASTableView.h @@ -219,9 +219,11 @@ NS_ASSUME_NONNULL_BEGIN - (void)endUpdatesAnimated:(BOOL)animated completion:(void (^ _Nullable)(BOOL completed))completion ASDISPLAYNODE_DEPRECATED_MSG("Use ASTableNode's -performBatchUpdates:completion: instead."); /** - * Blocks execution of the main thread until all section and row updates are committed. This method must be called from the main thread. + * See ASTableNode.h for full documentation of these methods. */ -- (void)waitUntilAllUpdatesAreCommitted ASDISPLAYNODE_DEPRECATED_MSG("Use ASTableNode method instead."); +@property (nonatomic, readonly) BOOL isProcessingUpdates; +- (void)onDidFinishProcessingUpdates:(nullable void (^)())completion; +- (void)waitUntilAllUpdatesAreCommitted ASDISPLAYNODE_DEPRECATED_MSG("Use -[ASTableNode waitUntilAllUpdatesAreProcessed] instead."); - (void)insertSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation ASDISPLAYNODE_DEPRECATED_MSG("Use ASTableNode method instead."); diff --git a/Source/ASTableView.mm b/Source/ASTableView.mm index d0e529c8b..d3f9a488d 100644 --- a/Source/ASTableView.mm +++ b/Source/ASTableView.mm @@ -548,7 +548,7 @@ - (void)reloadDataImmediately { ASDisplayNodeAssertMainThread(); [self reloadData]; - [_dataController waitUntilAllUpdatesAreCommitted]; + [_dataController waitUntilAllUpdatesAreProcessed]; } - (void)scrollToRowAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(UITableViewScrollPosition)scrollPosition animated:(BOOL)animated @@ -735,6 +735,16 @@ - (void)endUpdatesAnimated:(BOOL)animated completion:(void (^)(BOOL completed))c } } +- (BOOL)isProcessingUpdates +{ + return [_dataController isProcessingUpdates]; +} + +- (void)onDidFinishProcessingUpdates:(nullable void (^)())completion +{ + [_dataController onDidFinishProcessingUpdates:completion]; +} + - (void)waitUntilAllUpdatesAreCommitted { ASDisplayNodeAssertMainThread(); @@ -743,8 +753,8 @@ - (void)waitUntilAllUpdatesAreCommitted // ASDisplayNodeFailAssert(@"Should not call %@ during batch update", NSStringFromSelector(_cmd)); return; } - - [_dataController waitUntilAllUpdatesAreCommitted]; + + [_dataController waitUntilAllUpdatesAreProcessed]; } - (void)layoutSubviews diff --git a/Source/Details/ASDataController.h b/Source/Details/ASDataController.h index 82791a685..b2d2f3ab8 100644 --- a/Source/Details/ASDataController.h +++ b/Source/Details/ASDataController.h @@ -254,7 +254,12 @@ extern NSString * const ASCollectionInvalidUpdateException; */ - (void)relayoutNodes:(id)nodes nodesSizeChanged:(NSMutableArray * _Nonnull)nodesSizesChanged; -- (void)waitUntilAllUpdatesAreCommitted; +/** + * See ASCollectionNode.h for full documentation of these methods. + */ +@property (nonatomic, readonly) BOOL isProcessingUpdates; +- (void)onDidFinishProcessingUpdates:(nullable void (^)())completion; +- (void)waitUntilAllUpdatesAreProcessed; /** * Notifies the data controller object that its environment has changed. The object will request its environment delegate for new information diff --git a/Source/Details/ASDataController.mm b/Source/Details/ASDataController.mm index 102fca123..889599506 100644 --- a/Source/Details/ASDataController.mm +++ b/Source/Details/ASDataController.mm @@ -430,13 +430,42 @@ - (ASSizeRange)constrainedSizeForNodeOfKind:(NSString *)kind atIndexPath:(NSInde #pragma mark - Batching (External API) -- (void)waitUntilAllUpdatesAreCommitted +- (void)waitUntilAllUpdatesAreProcessed { // Schedule block in main serial queue to wait until all operations are finished that are // where scheduled while waiting for the _editingTransactionQueue to finish [self _scheduleBlockOnMainSerialQueue:^{ }]; } +- (BOOL)isProcessingUpdates +{ + ASDisplayNodeAssertMainThread(); + if (_mainSerialQueue.numberOfScheduledBlocks > 0) { + return YES; + } else if (dispatch_group_wait(_editingTransactionGroup, DISPATCH_TIME_NOW) != 0) { + // After waiting for zero duration, a nonzero value is returned if blocks are still running. + return YES; + } + // Both the _mainSerialQueue and _editingTransactionQueue are drained; we are fully quiesced. + return NO; +} + +- (void)onDidFinishProcessingUpdates:(nullable void (^)())completion +{ + ASDisplayNodeAssertMainThread(); + if ([self isProcessingUpdates] == NO) { + ASPerformBlockOnMainThread(completion); + } else { + dispatch_async(_editingTransactionQueue, ^{ + // Retry the block. If we're done processing updates, it'll run immediately, otherwise + // wait again for updates to quiesce completely. + [_mainSerialQueue performBlockOnMainThread:^{ + [self onDidFinishProcessingUpdates:completion]; + }]; + }); + } +} + - (void)updateWithChangeSet:(_ASHierarchyChangeSet *)changeSet { ASDisplayNodeAssertMainThread(); @@ -563,7 +592,7 @@ - (void)updateWithChangeSet:(_ASHierarchyChangeSet *)changeSet }); if (_usesSynchronousDataLoading) { - [self waitUntilAllUpdatesAreCommitted]; + [self waitUntilAllUpdatesAreProcessed]; } } diff --git a/Source/Details/ASMainSerialQueue.h b/Source/Details/ASMainSerialQueue.h index ef939effc..e94451d64 100644 --- a/Source/Details/ASMainSerialQueue.h +++ b/Source/Details/ASMainSerialQueue.h @@ -21,6 +21,7 @@ AS_SUBCLASSING_RESTRICTED @interface ASMainSerialQueue : NSObject +@property (nonatomic, readonly) NSUInteger numberOfScheduledBlocks; - (void)performBlockOnMainThread:(dispatch_block_t)block; @end diff --git a/Source/Details/ASMainSerialQueue.mm b/Source/Details/ASMainSerialQueue.mm index e79481fa4..4a3d929c1 100644 --- a/Source/Details/ASMainSerialQueue.mm +++ b/Source/Details/ASMainSerialQueue.mm @@ -40,6 +40,12 @@ - (instancetype)init return self; } +- (NSUInteger)numberOfScheduledBlocks +{ + ASDN::MutexLocker l(_serialQueueLock); + return _blocks.count; +} + - (void)performBlockOnMainThread:(dispatch_block_t)block { ASDN::MutexLocker l(_serialQueueLock); diff --git a/Tests/ASCollectionModernDataSourceTests.m b/Tests/ASCollectionModernDataSourceTests.m index a6daa9782..ff084a7b1 100644 --- a/Tests/ASCollectionModernDataSourceTests.m +++ b/Tests/ASCollectionModernDataSourceTests.m @@ -71,7 +71,7 @@ - (void)setUp { - (void)tearDown { - [collectionNode waitUntilAllUpdatesAreCommitted]; + [collectionNode waitUntilAllUpdatesAreProcessed]; [super tearDown]; } diff --git a/Tests/ASCollectionViewTests.mm b/Tests/ASCollectionViewTests.mm index 00cf58d2b..f3567b437 100644 --- a/Tests/ASCollectionViewTests.mm +++ b/Tests/ASCollectionViewTests.mm @@ -260,7 +260,7 @@ - (void)testSelection [window makeKeyAndVisible]; [testController.collectionNode reloadData]; - [testController.collectionNode waitUntilAllUpdatesAreCommitted]; + [testController.collectionNode waitUntilAllUpdatesAreProcessed]; [testController.collectionView layoutIfNeeded]; NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0]; @@ -397,7 +397,7 @@ - (void)testThatCollectionNodeConformsToExpectedProtocols window.rootViewController = testController;\ \ [cn reloadData];\ - [cn waitUntilAllUpdatesAreCommitted]; \ + [cn waitUntilAllUpdatesAreProcessed]; \ [testController.collectionView layoutIfNeeded]; - (void)testThatSubmittingAValidInsertDoesNotThrowAnException @@ -620,7 +620,7 @@ - (void)testThatDisappearingSupplementariesWithLayerBackedNodesDontFailAssert [window makeKeyAndVisible]; for (NSInteger i = 0; i < 2; i++) { - // NOTE: waitUntilAllUpdatesAreCommitted or reloadDataImmediately is not sufficient here!! + // NOTE: waitUntilAllUpdatesAreProcessed or reloadDataImmediately is not sufficient here!! XCTestExpectation *done = [self expectationWithDescription:[NSString stringWithFormat:@"Reload #%td complete", i]]; [cn reloadDataWithCompletion:^{ [done fulfill]; @@ -755,7 +755,7 @@ - (void)testThatSectionContextsAreCorrectAfterReloadData del.sectionGeneration++; [cn reloadData]; - [cn waitUntilAllUpdatesAreCommitted]; + [cn waitUntilAllUpdatesAreProcessed]; NSInteger sectionCount = del->_itemCounts.size(); for (NSInteger section = 0; section < sectionCount; section++) { @@ -857,7 +857,7 @@ - (void)testThatDeletedItemsAreMarkedInvisible [window layoutIfNeeded]; ASCollectionNode *cn = testController.collectionNode; - [cn waitUntilAllUpdatesAreCommitted]; + [cn waitUntilAllUpdatesAreProcessed]; [cn.view layoutIfNeeded]; ASCellNode *node = [cn nodeForItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]]; XCTAssertTrue(node.visible); @@ -880,7 +880,7 @@ - (void)testThatMultipleBatchFetchesDontHappenUnnecessarily [window layoutIfNeeded]; ASCollectionNode *cn = testController.collectionNode; - [cn waitUntilAllUpdatesAreCommitted]; + [cn waitUntilAllUpdatesAreProcessed]; XCTAssertGreaterThan(cn.bounds.size.height, cn.view.contentSize.height, @"Expected initial data not to fill collection view area."); __block NSUInteger batchFetchCount = 0; @@ -926,7 +926,7 @@ - (void)testThatBatchFetchHappensForEmptyCollection [window layoutIfNeeded]; ASCollectionNode *cn = testController.collectionNode; - [cn waitUntilAllUpdatesAreCommitted]; + [cn waitUntilAllUpdatesAreProcessed]; __block NSUInteger batchFetchCount = 0; XCTestExpectation *e = [self expectationWithDescription:@"Batch fetching completed"]; @@ -1020,7 +1020,7 @@ - (void)_primitiveBatchFetchingFillTestAnimated:(BOOL)animated visible:(BOOL)vis [view layoutIfNeeded]; // Wait for ASDK reload to finish - [cn waitUntilAllUpdatesAreCommitted]; + [cn waitUntilAllUpdatesAreProcessed]; // Force UIKit to read updated data & range controller to update and account for it [cn.view layoutIfNeeded]; [self waitForExpectationsWithTimeout:60 handler:nil]; @@ -1050,8 +1050,17 @@ - (void)testInitialRangeBounds // Trigger the initial reload to start [window layoutIfNeeded]; + // Test the APIs that monitor ASCollectionNode update handling + XCTAssertTrue(cn.isProcessingUpdates, @"ASCollectionNode should still be processing updates after initial layoutIfNeeded call (reloadData)"); + [cn onDidFinishProcessingUpdates:^{ + XCTAssertTrue(!cn.isProcessingUpdates, @"ASCollectionNode should no longer be processing updates inside -onDidFinishProcessingUpdates: block"); + }]; + // Wait for ASDK reload to finish - [cn waitUntilAllUpdatesAreCommitted]; + [cn waitUntilAllUpdatesAreProcessed]; + + XCTAssertTrue(!cn.isProcessingUpdates, @"ASCollectionNode should no longer be processing updates after -wait call"); + // Force UIKit to read updated data & range controller to update and account for it [cn.view layoutIfNeeded]; @@ -1093,7 +1102,7 @@ - (void)testTraitCollectionChangesMidUpdate traitCollection.containerSize = screenBounds.size; cn.primitiveTraitCollection = traitCollection; - [cn waitUntilAllUpdatesAreCommitted]; + [cn waitUntilAllUpdatesAreProcessed]; [cn.view layoutIfNeeded]; // Assert that the new trait collection is picked up by all cell nodes, including ones that were not allocated but are forced to allocate now @@ -1124,7 +1133,7 @@ - (void)DISABLED_testThatAutomaticallyManagedSubnodesGetPreloadCallBeforeDisplay [window makeKeyAndVisible]; [window layoutIfNeeded]; - [cn waitUntilAllUpdatesAreCommitted]; + [cn waitUntilAllUpdatesAreProcessed]; for (NSInteger i = 0; i < itemCount; i++) { ASTextCellNodeWithSetSelectedCounter *node = [cn nodeForItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]]; XCTAssert(node.automaticallyManagesSubnodes, @"Expected test cell node to use automatic subnode management. Can modify the test with a different class if needed."); diff --git a/Tests/ASTableViewTests.mm b/Tests/ASTableViewTests.mm index e7388ccf7..2bf793641 100644 --- a/Tests/ASTableViewTests.mm +++ b/Tests/ASTableViewTests.mm @@ -610,7 +610,7 @@ - (void)testThatInitialDataLoadHappensInOneShot [UITableView as_recordEditingCallsIntoArray:selectors]; XCTAssertGreaterThan(node.numberOfSections, 0); - [node waitUntilAllUpdatesAreCommitted]; + [node waitUntilAllUpdatesAreProcessed]; XCTAssertGreaterThan(node.view.numberOfSections, 0); // The first reloadData call helps prevent UITableView from calling it multiple times while ASDataController is working. @@ -635,13 +635,13 @@ - (void)testThatReloadDataHappensInOneShot // Load initial data. XCTAssertGreaterThan(node.numberOfSections, 0); - [node waitUntilAllUpdatesAreCommitted]; + [node waitUntilAllUpdatesAreProcessed]; XCTAssertGreaterThan(node.view.numberOfSections, 0); // Reload data. [UITableView as_recordEditingCallsIntoArray:selectors]; [node reloadData]; - [node waitUntilAllUpdatesAreCommitted]; + [node waitUntilAllUpdatesAreProcessed]; // Assert that the beginning of the call pattern is correct. // There is currently noise that comes after that we will allow for this test. @@ -668,7 +668,7 @@ - (void)testThatNodeConstrainedSizesAreCorrectIfReloadIsPreempted // Trigger data load BEFORE first layout pass, to ensure constrained size is correct. XCTAssertGreaterThan(node.numberOfSections, 0); - [node waitUntilAllUpdatesAreCommitted]; + [node waitUntilAllUpdatesAreProcessed]; ASSizeRange expectedSizeRange = ASSizeRangeMake(CGSizeMake(cellWidth, 0)); expectedSizeRange.max.height = CGFLOAT_MAX; @@ -703,7 +703,7 @@ - (void)testSectionIndexHandling // So we need to force a new layout pass so that the table will pick up a new constrained size and apply to its node. [node setNeedsLayout]; [node.view layoutIfNeeded]; - [node waitUntilAllUpdatesAreCommitted]; + [node waitUntilAllUpdatesAreProcessed]; UITableViewCell *cell = [node.view cellForRowAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]]; XCTAssertNotNil(cell); @@ -758,7 +758,7 @@ - (void)testIssue2252 [window makeKeyAndVisible]; [window layoutIfNeeded]; - [node waitUntilAllUpdatesAreCommitted]; + [node waitUntilAllUpdatesAreProcessed]; XCTAssertEqual(node.view.numberOfSections, NumberOfSections); ASXCTAssertEqualRects(CGRectMake(0, 32, 375, 44), [node rectForRowAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]], @"This text requires very specific geometry. The rect for the first row should match up."); @@ -812,7 +812,7 @@ - (void)testAutomaticallyAdjustingContentOffset node.dataSource = ds; [node.view layoutIfNeeded]; - [node waitUntilAllUpdatesAreCommitted]; + [node waitUntilAllUpdatesAreProcessed]; CGFloat rowHeight = [node.view rectForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]].size.height; // Scroll to row (0,1) + 10pt node.contentOffset = CGPointMake(0, rowHeight + 10); @@ -825,7 +825,7 @@ - (void)testAutomaticallyAdjustingContentOffset [node deleteRowsAtIndexPaths:@[ [NSIndexPath indexPathForItem:0 inSection:i]] withRowAnimation:UITableViewRowAnimationAutomatic]; } } completion:nil]; - [node waitUntilAllUpdatesAreCommitted]; + [node waitUntilAllUpdatesAreProcessed]; // 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.