mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-16 11:20:18 +00:00
[ASDataController] If app code issues edit commands before first reload, ignore them, as UIKit will call -reloadData.
This commit is contained in:
parent
354ccf3e5f
commit
cc7ca4a08f
@ -42,6 +42,8 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
|
|||||||
NSOperationQueue *_editingTransactionQueue; // Serial background queue. Dispatches concurrent layout and manages _editingNodes.
|
NSOperationQueue *_editingTransactionQueue; // Serial background queue. Dispatches concurrent layout and manages _editingNodes.
|
||||||
|
|
||||||
BOOL _asyncDataFetchingEnabled;
|
BOOL _asyncDataFetchingEnabled;
|
||||||
|
|
||||||
|
BOOL _initialReloadDataHasBeenCalled;
|
||||||
|
|
||||||
BOOL _delegateDidInsertNodes;
|
BOOL _delegateDidInsertNodes;
|
||||||
BOOL _delegateDidDeleteNodes;
|
BOOL _delegateDidDeleteNodes;
|
||||||
@ -267,7 +269,7 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG(@"_deleteNodesAtIndexPaths:%@ ofKind:%@, full index paths in _editingNodes = %@", indexPaths, kind, ASIndexPathsForMultidimensionalArray(_editingNodes[kind]));
|
LOG(@"_deleteNodesAtIndexPaths:%@ ofKind:%@, full index paths in _editingNodes = %@", indexPaths, kind, ASIndexPathsForTwoDimensionalArray(_editingNodes[kind]));
|
||||||
NSMutableArray *editingNodes = _editingNodes[kind];
|
NSMutableArray *editingNodes = _editingNodes[kind];
|
||||||
ASDeleteElementsInMultidimensionalArrayAtIndexPaths(editingNodes, indexPaths);
|
ASDeleteElementsInMultidimensionalArrayAtIndexPaths(editingNodes, indexPaths);
|
||||||
_editingNodes[kind] = editingNodes;
|
_editingNodes[kind] = editingNodes;
|
||||||
@ -376,32 +378,6 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
|
|||||||
|
|
||||||
#pragma mark - Initial Load & Full Reload (External API)
|
#pragma mark - Initial Load & Full Reload (External API)
|
||||||
|
|
||||||
- (void)initialDataLoadingWithAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
|
|
||||||
{
|
|
||||||
[self performEditCommandWithBlock:^{
|
|
||||||
ASDisplayNodeAssertMainThread();
|
|
||||||
[self accessDataSourceWithBlock:^{
|
|
||||||
NSMutableArray *indexPaths = [NSMutableArray array];
|
|
||||||
NSUInteger sectionNum = [_dataSource numberOfSectionsInDataController:self];
|
|
||||||
|
|
||||||
// insert sections
|
|
||||||
[self insertSections:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, sectionNum)] withAnimationOptions:0];
|
|
||||||
|
|
||||||
for (NSUInteger i = 0; i < sectionNum; i++) {
|
|
||||||
NSIndexPath *indexPath = [[NSIndexPath alloc] initWithIndex:i];
|
|
||||||
|
|
||||||
NSUInteger rowNum = [_dataSource dataController:self rowsInSection:i];
|
|
||||||
for (NSUInteger j = 0; j < rowNum; j++) {
|
|
||||||
[indexPaths addObject:[indexPath indexPathByAddingIndex:j]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// insert elements
|
|
||||||
[self insertRowsAtIndexPaths:indexPaths withAnimationOptions:animationOptions];
|
|
||||||
}];
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)reloadDataWithAnimationOptions:(ASDataControllerAnimationOptions)animationOptions completion:(void (^)())completion
|
- (void)reloadDataWithAnimationOptions:(ASDataControllerAnimationOptions)animationOptions completion:(void (^)())completion
|
||||||
{
|
{
|
||||||
[self _reloadDataWithAnimationOptions:animationOptions synchronously:NO completion:completion];
|
[self _reloadDataWithAnimationOptions:animationOptions synchronously:NO completion:completion];
|
||||||
@ -414,6 +390,7 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
|
|||||||
|
|
||||||
- (void)_reloadDataWithAnimationOptions:(ASDataControllerAnimationOptions)animationOptions synchronously:(BOOL)synchronously completion:(void (^)())completion
|
- (void)_reloadDataWithAnimationOptions:(ASDataControllerAnimationOptions)animationOptions synchronously:(BOOL)synchronously completion:(void (^)())completion
|
||||||
{
|
{
|
||||||
|
_initialReloadDataHasBeenCalled = YES;
|
||||||
[self performEditCommandWithBlock:^{
|
[self performEditCommandWithBlock:^{
|
||||||
ASDisplayNodeAssertMainThread();
|
ASDisplayNodeAssertMainThread();
|
||||||
[_editingTransactionQueue waitUntilAllOperationsAreFinished];
|
[_editingTransactionQueue waitUntilAllOperationsAreFinished];
|
||||||
@ -430,12 +407,14 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
|
|||||||
LOG(@"Edit Transaction - reloadData");
|
LOG(@"Edit Transaction - reloadData");
|
||||||
|
|
||||||
// Remove everything that existed before the reload, now that we're ready to insert replacements
|
// Remove everything that existed before the reload, now that we're ready to insert replacements
|
||||||
NSArray *indexPaths = ASIndexPathsForMultidimensionalArray(_editingNodes[ASDataControllerRowNodeKind]);
|
|
||||||
[self _deleteNodesAtIndexPaths:indexPaths withAnimationOptions:animationOptions];
|
|
||||||
|
|
||||||
NSMutableArray *editingNodes = _editingNodes[ASDataControllerRowNodeKind];
|
NSMutableArray *editingNodes = _editingNodes[ASDataControllerRowNodeKind];
|
||||||
NSMutableIndexSet *indexSet = [[NSMutableIndexSet alloc] initWithIndexesInRange:NSMakeRange(0, editingNodes.count)];
|
NSUInteger editingNodesSectionCount = editingNodes.count;
|
||||||
[self _deleteSectionsAtIndexSet:indexSet withAnimationOptions:animationOptions];
|
|
||||||
|
if (editingNodesSectionCount) {
|
||||||
|
NSMutableIndexSet *indexSet = [[NSMutableIndexSet alloc] initWithIndexesInRange:NSMakeRange(0, editingNodesSectionCount)];
|
||||||
|
[self _deleteNodesAtIndexPaths:ASIndexPathsForTwoDimensionalArray(editingNodes) withAnimationOptions:animationOptions];
|
||||||
|
[self _deleteSectionsAtIndexSet:indexSet withAnimationOptions:animationOptions];
|
||||||
|
}
|
||||||
|
|
||||||
[self willReloadData];
|
[self willReloadData];
|
||||||
|
|
||||||
@ -591,6 +570,12 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
|
|||||||
{
|
{
|
||||||
// This method needs to block the thread and synchronously perform the operation if we are not
|
// This method needs to block the thread and synchronously perform the operation if we are not
|
||||||
// queuing commands for begin/endUpdates. If we are queuing, it needs to return immediately.
|
// queuing commands for begin/endUpdates. If we are queuing, it needs to return immediately.
|
||||||
|
if (!_initialReloadDataHasBeenCalled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have never performed a reload, there is no value in executing edit operations as the initial
|
||||||
|
// reload will directly re-query the latest state of the datasource - so completely skip the block in this case.
|
||||||
if (_batchUpdateCounter == 0) {
|
if (_batchUpdateCounter == 0) {
|
||||||
block();
|
block();
|
||||||
} else {
|
} else {
|
||||||
@ -667,7 +652,7 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
|
|||||||
|
|
||||||
NSArray *indexPaths = ASIndexPathsForMultidimensionalArrayAtIndexSet(_editingNodes[ASDataControllerRowNodeKind], sections);
|
NSArray *indexPaths = ASIndexPathsForMultidimensionalArrayAtIndexSet(_editingNodes[ASDataControllerRowNodeKind], sections);
|
||||||
|
|
||||||
LOG(@"Edit Transaction - reloadSections: updatedIndexPaths: %@, indexPaths: %@, _editingNodes: %@", updatedIndexPaths, indexPaths, ASIndexPathsForMultidimensionalArray(_editingNodes[ASDataControllerRowNodeKind]));
|
LOG(@"Edit Transaction - reloadSections: updatedIndexPaths: %@, indexPaths: %@, _editingNodes: %@", updatedIndexPaths, indexPaths, ASIndexPathsForTwoDimensionalArray(_editingNodes[ASDataControllerRowNodeKind]));
|
||||||
|
|
||||||
[self _deleteNodesAtIndexPaths:indexPaths withAnimationOptions:animationOptions];
|
[self _deleteNodesAtIndexPaths:indexPaths withAnimationOptions:animationOptions];
|
||||||
|
|
||||||
@ -900,7 +885,7 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
|
|||||||
|
|
||||||
- (NSArray *)indexPathsForEditingNodesOfKind:(NSString *)kind
|
- (NSArray *)indexPathsForEditingNodesOfKind:(NSString *)kind
|
||||||
{
|
{
|
||||||
return _editingNodes[kind] != nil ? ASIndexPathsForMultidimensionalArray(_editingNodes[kind]) : nil;
|
return _editingNodes[kind] != nil ? ASIndexPathsForTwoDimensionalArray(_editingNodes[kind]) : nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSMutableArray *)editingNodesOfKind:(NSString *)kind
|
- (NSMutableArray *)editingNodesOfKind:(NSString *)kind
|
||||||
|
|||||||
@ -65,4 +65,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSString *)description
|
||||||
|
{
|
||||||
|
return [[super description] stringByAppendingFormat:@" Blocks: %@", _blocks];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@ -50,7 +50,12 @@ extern NSArray *ASFindElementsInMultidimensionalArrayAtIndexPaths(NSMutableArray
|
|||||||
extern NSArray *ASIndexPathsForMultidimensionalArrayAtIndexSet(NSArray *MultidimensionalArray, NSIndexSet *indexSet);
|
extern NSArray *ASIndexPathsForMultidimensionalArrayAtIndexSet(NSArray *MultidimensionalArray, NSIndexSet *indexSet);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return all the index paths of mutable multidimensional array, in ascending order.
|
* Return all the index paths of a two-dimensional array, in ascending order.
|
||||||
|
*/
|
||||||
|
extern NSArray *ASIndexPathsForTwoDimensionalArray(NSArray <NSArray *>* twoDimensionalArray);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return all the index paths of a multidimensional array, in ascending order.
|
||||||
*/
|
*/
|
||||||
extern NSArray *ASIndexPathsForMultidimensionalArray(NSArray *MultidimensionalArray);
|
extern NSArray *ASIndexPathsForMultidimensionalArray(NSArray *MultidimensionalArray);
|
||||||
|
|
||||||
|
|||||||
@ -16,7 +16,8 @@ static void ASRecursivelyUpdateMultidimensionalArrayAtIndexPaths(NSMutableArray
|
|||||||
NSUInteger &curIdx,
|
NSUInteger &curIdx,
|
||||||
NSIndexPath *curIndexPath,
|
NSIndexPath *curIndexPath,
|
||||||
const NSUInteger dimension,
|
const NSUInteger dimension,
|
||||||
void (^updateBlock)(NSMutableArray *arr, NSIndexSet *indexSet, NSUInteger idx)) {
|
void (^updateBlock)(NSMutableArray *arr, NSIndexSet *indexSet, NSUInteger idx))
|
||||||
|
{
|
||||||
if (curIdx == indexPaths.count) {
|
if (curIdx == indexPaths.count) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -38,7 +39,8 @@ static void ASRecursivelyUpdateMultidimensionalArrayAtIndexPaths(NSMutableArray
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ASRecursivelyFindIndexPathsForMultidimensionalArray(NSObject *obj, NSIndexPath *curIndexPath, NSMutableArray *res) {
|
static void ASRecursivelyFindIndexPathsForMultidimensionalArray(NSObject *obj, NSIndexPath *curIndexPath, NSMutableArray *res)
|
||||||
|
{
|
||||||
if (![obj isKindOfClass:[NSArray class]]) {
|
if (![obj isKindOfClass:[NSArray class]]) {
|
||||||
[res addObject:curIndexPath];
|
[res addObject:curIndexPath];
|
||||||
} else {
|
} else {
|
||||||
@ -51,7 +53,8 @@ static void ASRecursivelyFindIndexPathsForMultidimensionalArray(NSObject *obj, N
|
|||||||
|
|
||||||
#pragma mark - Public Methods
|
#pragma mark - Public Methods
|
||||||
|
|
||||||
NSObject<NSCopying> *ASMultidimensionalArrayDeepMutableCopy(NSObject<NSCopying> *obj) {
|
NSObject<NSCopying> *ASMultidimensionalArrayDeepMutableCopy(NSObject<NSCopying> *obj)
|
||||||
|
{
|
||||||
if ([obj isKindOfClass:[NSArray class]]) {
|
if ([obj isKindOfClass:[NSArray class]]) {
|
||||||
NSArray *arr = (NSArray *)obj;
|
NSArray *arr = (NSArray *)obj;
|
||||||
NSMutableArray * mutableArr = [NSMutableArray arrayWithCapacity:arr.count];
|
NSMutableArray * mutableArr = [NSMutableArray arrayWithCapacity:arr.count];
|
||||||
@ -64,15 +67,18 @@ NSObject<NSCopying> *ASMultidimensionalArrayDeepMutableCopy(NSObject<NSCopying>
|
|||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSMutableArray<NSMutableArray *> *ASTwoDimensionalArrayDeepMutableCopy(NSArray<NSArray *> *array) {
|
NSMutableArray<NSMutableArray *> *ASTwoDimensionalArrayDeepMutableCopy(NSArray<NSArray *> *array)
|
||||||
|
{
|
||||||
NSMutableArray *newArray = [NSMutableArray arrayWithCapacity:array.count];
|
NSMutableArray *newArray = [NSMutableArray arrayWithCapacity:array.count];
|
||||||
for (NSArray *subarray in array) {
|
for (NSArray *subarray in array) {
|
||||||
|
ASDisplayNodeCAssert([subarray isKindOfClass:[NSArray class]], @"This function expects NSArray<NSArray *> *");
|
||||||
[newArray addObject:[subarray mutableCopy]];
|
[newArray addObject:[subarray mutableCopy]];
|
||||||
}
|
}
|
||||||
return newArray;
|
return newArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASInsertElementsIntoMultidimensionalArrayAtIndexPaths(NSMutableArray *mutableArray, NSArray *indexPaths, NSArray *elements) {
|
void ASInsertElementsIntoMultidimensionalArrayAtIndexPaths(NSMutableArray *mutableArray, NSArray *indexPaths, NSArray *elements)
|
||||||
|
{
|
||||||
ASDisplayNodeCAssert(indexPaths.count == elements.count, @"Inconsistent indexPaths and elements");
|
ASDisplayNodeCAssert(indexPaths.count == elements.count, @"Inconsistent indexPaths and elements");
|
||||||
|
|
||||||
if (!indexPaths.count) {
|
if (!indexPaths.count) {
|
||||||
@ -89,7 +95,8 @@ void ASInsertElementsIntoMultidimensionalArrayAtIndexPaths(NSMutableArray *mutab
|
|||||||
ASDisplayNodeCAssert(curIdx == indexPaths.count, @"Indexpath is out of range !");
|
ASDisplayNodeCAssert(curIdx == indexPaths.count, @"Indexpath is out of range !");
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASDeleteElementsInMultidimensionalArrayAtIndexPaths(NSMutableArray *mutableArray, NSArray *indexPaths) {
|
void ASDeleteElementsInMultidimensionalArrayAtIndexPaths(NSMutableArray *mutableArray, NSArray *indexPaths)
|
||||||
|
{
|
||||||
if (!indexPaths.count) {
|
if (!indexPaths.count) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -104,7 +111,8 @@ void ASDeleteElementsInMultidimensionalArrayAtIndexPaths(NSMutableArray *mutable
|
|||||||
ASDisplayNodeCAssert(curIdx == indexPaths.count, @"Indexpath is out of range !");
|
ASDisplayNodeCAssert(curIdx == indexPaths.count, @"Indexpath is out of range !");
|
||||||
}
|
}
|
||||||
|
|
||||||
NSArray *ASFindElementsInMultidimensionalArrayAtIndexPaths(NSMutableArray *mutableArray, NSArray *indexPaths) {
|
NSArray *ASFindElementsInMultidimensionalArrayAtIndexPaths(NSMutableArray *mutableArray, NSArray *indexPaths)
|
||||||
|
{
|
||||||
NSUInteger curIdx = 0;
|
NSUInteger curIdx = 0;
|
||||||
NSIndexPath *indexPath = [[NSIndexPath alloc] init];
|
NSIndexPath *indexPath = [[NSIndexPath alloc] init];
|
||||||
NSMutableArray *deletedElements = [[NSMutableArray alloc] initWithCapacity:indexPaths.count];
|
NSMutableArray *deletedElements = [[NSMutableArray alloc] initWithCapacity:indexPaths.count];
|
||||||
@ -122,8 +130,9 @@ NSArray *ASFindElementsInMultidimensionalArrayAtIndexPaths(NSMutableArray *mutab
|
|||||||
return deletedElements;
|
return deletedElements;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSArray *ASIndexPathsForMultidimensionalArrayAtIndexSet(NSArray *multidimensionalArray, NSIndexSet *indexSet) {
|
NSArray *ASIndexPathsForMultidimensionalArrayAtIndexSet(NSArray *multidimensionalArray, NSIndexSet *indexSet)
|
||||||
NSMutableArray *res = [[NSMutableArray alloc] initWithCapacity:multidimensionalArray.count];
|
{
|
||||||
|
NSMutableArray *res = [NSMutableArray array];
|
||||||
[indexSet enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
|
[indexSet enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
|
||||||
ASRecursivelyFindIndexPathsForMultidimensionalArray(multidimensionalArray[idx], [NSIndexPath indexPathWithIndex:idx], res);
|
ASRecursivelyFindIndexPathsForMultidimensionalArray(multidimensionalArray[idx], [NSIndexPath indexPathWithIndex:idx], res);
|
||||||
}];
|
}];
|
||||||
@ -131,9 +140,24 @@ NSArray *ASIndexPathsForMultidimensionalArrayAtIndexSet(NSArray *multidimensiona
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSArray *ASIndexPathsForMultidimensionalArray(NSArray *multidimensionalArray) {
|
NSArray *ASIndexPathsForTwoDimensionalArray(NSArray <NSArray *>* twoDimensionalArray)
|
||||||
NSMutableArray *res = [NSMutableArray arrayWithCapacity:multidimensionalArray.count];
|
{
|
||||||
|
NSMutableArray *result = [NSMutableArray array];
|
||||||
|
NSUInteger section = 0;
|
||||||
|
for (NSArray *subarray in twoDimensionalArray) {
|
||||||
|
ASDisplayNodeCAssert([subarray isKindOfClass:[NSArray class]], @"This function expects NSArray<NSArray *> *");
|
||||||
|
NSUInteger itemCount = subarray.count;
|
||||||
|
for (int item = 0; item < itemCount; item++) {
|
||||||
|
[result addObject:[NSIndexPath indexPathForItem:item inSection:section]];
|
||||||
|
}
|
||||||
|
section++;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSArray *ASIndexPathsForMultidimensionalArray(NSArray *multidimensionalArray)
|
||||||
|
{
|
||||||
|
NSMutableArray *res = [NSMutableArray array];
|
||||||
ASRecursivelyFindIndexPathsForMultidimensionalArray(multidimensionalArray, [[NSIndexPath alloc] init], res);
|
ASRecursivelyFindIndexPathsForMultidimensionalArray(multidimensionalArray, [[NSIndexPath alloc] init], res);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user