PR Feedback: Require main thread for all edit commands, various cleanup.

This commit is contained in:
Ethan Nagel 2015-07-20 22:08:19 -07:00
parent f497639124
commit bf0766169b
5 changed files with 47 additions and 45 deletions

View File

@ -79,9 +79,8 @@
@property (nonatomic, assign) CGFloat leadingScreensForBatching;
/**
* Perform a batch of updates asynchronously, optionally disabling all animations in the batch. You can call it from background
* thread (it is recommendated) and the UI collection view will be updated asynchronously. The asyncDataSource must be updated
* to reflect the changes before this method is called.
* Perform a batch of updates asynchronously, optionally disabling all animations in the batch. This method must be called from the main thread.
* The asyncDataSource must be updated to reflect the changes before the update block completes.
*
* @param animated NO to disable animations for this batch
* @param updates The block that performs the relevant insert, delete, reload, or move operations.
@ -92,8 +91,8 @@
- (void)performBatchAnimated:(BOOL)animated updates:(void (^)())updates completion:(void (^)(BOOL))completion;
/**
* Perform a batch of updates asynchronously. You can call it from background thread (it is recommendated) and the UI collection
* view will be updated asynchronously. The asyncDataSource must be updated to reflect the changes before this method is called.
* Perform a batch of updates asynchronously. This method must be called from the main thread.
* The asyncDataSource must be updated to reflect the changes before update block completes.
*
* @param updates The block that performs the relevant insert, delete, reload, or move operations.
* @param completion A completion handler block to execute when all of the operations are finished. This block takes a single
@ -123,8 +122,7 @@
*
* @param sections An index set that specifies the sections to insert.
*
* @discussion This operation is asynchronous and thread safe. You can call it from background thread (it is recommendated)
* and the UI collection view will be updated asynchronously. The asyncDataSource must be updated to reflect the changes
* @discussion This method must be called from the main thread. The asyncDataSource must be updated to reflect the changes
* before this method is called.
*/
- (void)insertSections:(NSIndexSet *)sections;
@ -134,8 +132,7 @@
*
* @param sections An index set that specifies the sections to delete.
*
* @discussion This operation is asynchronous and thread safe. You can call it from background thread (it is recommendated)
* and the UI collection view will be updated asynchronously. The asyncDataSource must be updated to reflect the changes
* @discussion This method must be called from the main thread. The asyncDataSource must be updated to reflect the changes
* before this method is called.
*/
- (void)deleteSections:(NSIndexSet *)sections;
@ -145,8 +142,7 @@
*
* @param sections An index set that specifies the sections to reload.
*
* @discussion This operation is asynchronous and thread safe. You can call it from background thread (it is recommendated)
* and the UI collection view will be updated asynchronously. The asyncDataSource must be updated to reflect the changes
* @discussion This method must be called from the main thread. The asyncDataSource must be updated to reflect the changes
* before this method is called.
*/
- (void)reloadSections:(NSIndexSet *)sections;
@ -158,8 +154,7 @@
*
* @param newSection The index that is the destination of the move for the section.
*
* @discussion This operation is asynchronous and thread safe. You can call it from background thread (it is recommendated)
* and the UI collection view will be updated asynchronously. The asyncDataSource must be updated to reflect the changes
* @discussion This method must be called from the main thread. The asyncDataSource must be updated to reflect the changes
* before this method is called.
*/
- (void)moveSection:(NSInteger)section toSection:(NSInteger)newSection;
@ -169,8 +164,7 @@
*
* @param indexPaths An array of NSIndexPath objects, each representing an item index and section index that together identify an item.
*
* @discussion This operation is asynchronous and thread safe. You can call it from background thread (it is recommendated)
* and the UI collection view will be updated asynchronously. The asyncDataSource must be updated to reflect the changes
* @discussion This method must be called from the main thread. The asyncDataSource must be updated to reflect the changes
* before this method is called.
*/
- (void)insertItemsAtIndexPaths:(NSArray *)indexPaths;
@ -180,8 +174,7 @@
*
* @param indexPaths An array of NSIndexPath objects identifying the items to delete.
*
* @discussion This operation is asynchronous and thread safe. You can call it from background thread (it is recommendated)
* and the UI collection view will be updated asynchronously. The asyncDataSource must be updated to reflect the changes
* @discussion This method must be called from the main thread. The asyncDataSource must be updated to reflect the changes
* before this method is called.
*/
- (void)deleteItemsAtIndexPaths:(NSArray *)indexPaths;
@ -191,8 +184,7 @@
*
* @param indexPaths An array of NSIndexPath objects identifying the items to reload.
*
* @discussion This operation is asynchronous and thread safe. You can call it from background thread (it is recommendated)
* and the UI collection view will be updated asynchronously. The asyncDataSource must be updated to reflect the changes
* @discussion This method must be called from the main thread. The asyncDataSource must be updated to reflect the changes
* before this method is called.
*/
- (void)reloadItemsAtIndexPaths:(NSArray *)indexPaths;
@ -204,8 +196,7 @@
*
* @param newIndexPath The index path that is the destination of the move for the item.
*
* @discussion This operation is asynchronous and thread safe. You can call it from background thread (it is recommendated)
* and the UI collection view will be updated asynchronously. The asyncDataSource must be updated to reflect the changes
* @discussion This method must be called from the main thread. The asyncDataSource must be updated to reflect the changes
* before this method is called.
*/
- (void)moveItemAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath;

View File

@ -283,6 +283,8 @@ static BOOL _isInterceptedSelector(SEL sel)
- (void)performBatchAnimated:(BOOL)animated updates:(void (^)())updates completion:(void (^)(BOOL))completion
{
ASDisplayNodeAssertMainThread();
[_dataController beginUpdates];
updates();
[_dataController endUpdatesAnimated:animated completion:completion];
@ -295,41 +297,49 @@ static BOOL _isInterceptedSelector(SEL sel)
- (void)insertSections:(NSIndexSet *)sections
{
ASDisplayNodeAssertMainThread();
[_dataController insertSections:sections withAnimationOptions:kASCollectionViewAnimationNone];
}
- (void)deleteSections:(NSIndexSet *)sections
{
ASDisplayNodeAssertMainThread();
[_dataController deleteSections:sections withAnimationOptions:kASCollectionViewAnimationNone];
}
- (void)reloadSections:(NSIndexSet *)sections
{
ASDisplayNodeAssertMainThread();
[_dataController reloadSections:sections withAnimationOptions:kASCollectionViewAnimationNone];
}
- (void)moveSection:(NSInteger)section toSection:(NSInteger)newSection
{
ASDisplayNodeAssertMainThread();
[_dataController moveSection:section toSection:newSection withAnimationOptions:kASCollectionViewAnimationNone];
}
- (void)insertItemsAtIndexPaths:(NSArray *)indexPaths
{
ASDisplayNodeAssertMainThread();
[_dataController insertRowsAtIndexPaths:indexPaths withAnimationOptions:kASCollectionViewAnimationNone];
}
- (void)deleteItemsAtIndexPaths:(NSArray *)indexPaths
{
ASDisplayNodeAssertMainThread();
[_dataController deleteRowsAtIndexPaths:indexPaths withAnimationOptions:kASCollectionViewAnimationNone];
}
- (void)reloadItemsAtIndexPaths:(NSArray *)indexPaths
{
ASDisplayNodeAssertMainThread();
[_dataController reloadRowsAtIndexPaths:indexPaths withAnimationOptions:kASCollectionViewAnimationNone];
}
- (void)moveItemAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath
{
ASDisplayNodeAssertMainThread();
[_dataController moveRowAtIndexPath:indexPath toIndexPath:newIndexPath withAnimationOptions:kASCollectionViewAnimationNone];
}

View File

@ -94,7 +94,7 @@
- (void)reloadData;
/**
* begins a batch of insert, delete reload and move operations. Batches are asynchronous an thread safe.
* begins a batch of insert, delete reload and move operations. This method must be called from the main thread.
*/
- (void)beginUpdates;
@ -102,7 +102,7 @@
* Concludes a series of method calls that insert, delete, select, or reload rows and sections of the table view.
* You call this method to bracket a series of method calls that begins with beginUpdates and that consists of operations
* to insert, delete, select, and reload rows and sections of the table view. When you call endUpdates, ASTableView begins animating
* the operations simultaneously. This method is asynchronous and thread safe. It's important to remeber that the ASTableView will
* the operations simultaneously. This method is must be called from the main thread. It's important to remeber that the ASTableView will
* be processing the updates asynchronously after this call is completed.
*
* @param animated NO to disable all animations.
@ -116,7 +116,7 @@
* Concludes a series of method calls that insert, delete, select, or reload rows and sections of the table view.
* You call this method to bracket a series of method calls that begins with beginUpdates and that consists of operations
* to insert, delete, select, and reload rows and sections of the table view. When you call endUpdates, ASTableView begins animating
* the operations simultaneously. This method is asynchronous and thread safe. It's important to remeber that the ASTableView will
* the operations simultaneously. This method is must be called from the main thread. It's important to remeber that the ASTableView will
* be processing the updates asynchronously after this call and are not guaranteed to be reflected in the ASTableView until
* the completion block is executed.
*
@ -134,8 +134,7 @@
*
* @param animation A constant that indicates how the insertion is to be animated. See UITableViewRowAnimation.
*
* @discussion This operation is asynchronous and thread safe. You can call it from background thread (it is recommendated)
* and the UI table view will be updated asynchronously. The asyncDataSource must be updated to reflect the changes
* @discussion This method must be called from the main thread. The asyncDataSource must be updated to reflect the changes
* before this method is called.
*/
- (void)insertSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation;
@ -147,8 +146,7 @@
*
* @param animation A constant that indicates how the deletion is to be animated. See UITableViewRowAnimation.
*
* @discussion This operation is asynchronous and thread safe. You can call it from background thread (it is recommendated)
* and the UI table view will be updated asynchronously. The asyncDataSource must be updated to reflect the changes
* @discussion This method must be called from the main thread. The asyncDataSource must be updated to reflect the changes
* before this method is called.
*/
- (void)deleteSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation;
@ -160,8 +158,7 @@
*
* @param animation A constant that indicates how the reloading is to be animated. See UITableViewRowAnimation.
*
* @discussion This operation is asynchronous and thread safe. You can call it from background thread (it is recommendated)
* and the UI table view will be updated asynchronously. The asyncDataSource must be updated to reflect the changes
* @discussion This method must be called from the main thread. The asyncDataSource must be updated to reflect the changes
* before this method is called.
*/
- (void)reloadSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation;
@ -173,8 +170,7 @@
*
* @param newSection The index that is the destination of the move for the section.
*
* @discussion This operation is asynchronous and thread safe. You can call it from background thread (it is recommendated)
* and the UI table view will be updated asynchronously. The asyncDataSource must be updated to reflect the changes
* @discussion This method must be called from the main thread. The asyncDataSource must be updated to reflect the changes
* before this method is called.
*/
- (void)moveSection:(NSInteger)section toSection:(NSInteger)newSection;
@ -186,8 +182,7 @@
*
* @param animation A constant that indicates how the insertion is to be animated. See UITableViewRowAnimation.
*
* @discussion This operation is asynchronous and thread safe. You can call it from background thread (it is recommendated)
* and the UI table view will be updated asynchronously. The asyncDataSource must be updated to reflect the changes
* @discussion This method must be called from the main thread. The asyncDataSource must be updated to reflect the changes
* before this method is called.
*/
- (void)insertRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;
@ -199,8 +194,7 @@
*
* @param animation A constant that indicates how the deletion is to be animated. See UITableViewRowAnimation.
*
* @discussion This operation is asynchronous and thread safe. You can call it from background thread (it is recommendated)
* and the UI table view will be updated asynchronously. The asyncDataSource must be updated to reflect the changes
* @discussion This method must be called from the main thread. The asyncDataSource must be updated to reflect the changes
* before this method is called.
*/
- (void)deleteRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;
@ -212,8 +206,7 @@
*
* @param animation A constant that indicates how the reloading is to be animated. See UITableViewRowAnimation.
*
* @discussion This operation is asynchronous and thread safe. You can call it from background thread (it is recommendated)
* and the UI table view will be updated asynchronously. The asyncDataSource must be updated to reflect the changes
* @discussion This method must be called from the main thread. The asyncDataSource must be updated to reflect the changes
* before this method is called.
*/
- (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;
@ -225,8 +218,7 @@
*
* @param newIndexPath The index path that is the destination of the move for the row.
*
* @discussion This operation is asynchronous and thread safe. You can call it from background thread (it is recommendated)
* and the UI table view will be updated asynchronously. The asyncDataSource must be updated to reflect the changes
* @discussion This method must be called from the main thread. The asyncDataSource must be updated to reflect the changes
* before this method is called.
*/
- (void)moveRowAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath;
@ -249,7 +241,8 @@
/**
* YES to automatically adjust the contentOffset when cells are inserted or deleted "before"
* visible cells, maintaining the users' visible scroll position.
* visible cells, maintaining the users' visible scroll position. Currently this feature tracks insertions, moves and deletions of
* cells, but section edits are ignored.
*
* default is NO.
*/

View File

@ -328,6 +328,7 @@ void ASPerformBlockWithoutAnimation(BOOL withoutAnimation, void (^block)()) {
- (void)beginUpdates
{
ASDisplayNodeAssertMainThread();
[_dataController beginUpdates];
}
@ -338,6 +339,7 @@ void ASPerformBlockWithoutAnimation(BOOL withoutAnimation, void (^block)()) {
- (void)endUpdatesAnimated:(BOOL)animated completion:(void (^)(BOOL completed))completion;
{
ASDisplayNodeAssertMainThread();
[_dataController endUpdatesAnimated:animated completion:completion];
}
@ -346,41 +348,49 @@ void ASPerformBlockWithoutAnimation(BOOL withoutAnimation, void (^block)()) {
- (void)insertSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation
{
ASDisplayNodeAssertMainThread();
[_dataController insertSections:sections withAnimationOptions:animation];
}
- (void)deleteSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation
{
ASDisplayNodeAssertMainThread();
[_dataController deleteSections:sections withAnimationOptions:animation];
}
- (void)reloadSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation
{
ASDisplayNodeAssertMainThread();
[_dataController reloadSections:sections withAnimationOptions:animation];
}
- (void)moveSection:(NSInteger)section toSection:(NSInteger)newSection
{
ASDisplayNodeAssertMainThread();
[_dataController moveSection:section toSection:newSection withAnimationOptions:UITableViewRowAnimationNone];
}
- (void)insertRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation
{
ASDisplayNodeAssertMainThread();
[_dataController insertRowsAtIndexPaths:indexPaths withAnimationOptions:animation];
}
- (void)deleteRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation
{
ASDisplayNodeAssertMainThread();
[_dataController deleteRowsAtIndexPaths:indexPaths withAnimationOptions:animation];
}
- (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation
{
ASDisplayNodeAssertMainThread();
[_dataController reloadRowsAtIndexPaths:indexPaths withAnimationOptions:animation];
}
- (void)moveRowAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath
{
ASDisplayNodeAssertMainThread();
[_dataController moveRowAtIndexPath:indexPath toIndexPath:newIndexPath withAnimationOptions:UITableViewRowAnimationNone];
}
@ -416,7 +426,7 @@ void ASPerformBlockWithoutAnimation(BOOL withoutAnimation, void (^block)()) {
CGFloat adjustment = 0;
NSIndexPath *top = _contentOffsetAdjustmentTopVisibleRow ?: self.indexPathsForVisibleRows.firstObject;
for (int index=0; index<indexPaths.count; index++) {
for (int index = 0; index < indexPaths.count; index++) {
NSIndexPath *indexPath = indexPaths[index];
if ([indexPath compare:top] <= 0) { // if this row is before or equal to the topmost visible row, make adjustments...
ASCellNode *cellNode = nodes[index];
@ -429,7 +439,7 @@ void ASPerformBlockWithoutAnimation(BOOL withoutAnimation, void (^block)()) {
if (_contentOffsetAdjustmentTopVisibleRow) { // true of we are in a begin/end update block (see beginAdjustingContentOffset)
_contentOffsetAdjustmentTopVisibleRow = top;
_contentOffsetAdjustment += adjustment;
_contentOffsetAdjustment += adjustment;
} else if (adjustment != 0) {
self.contentOffset = CGPointMake(0, self.contentOffset.y+adjustment);
}

View File

@ -328,8 +328,6 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
[_editingTransactionQueue waitUntilAllOperationsAreFinished];
// Begin queuing up edit calls that happen on the main thread.
// This will prevent further operations from being scheduled on _editingTransactionQueue.
// It's fine if there is an in-flight operation on _editingTransactionQueue,
// as once the command queue is unpaused, each edit command will wait for the _editingTransactionQueue to be flushed.
_batchUpdateCounter++;
}