UICollectionView BatchUpdate边缘情况失败

Dav*_*ave 4 objective-c uikit ios uicollectionview performbatchupdates

我在UICollectionView的batchUpdate操作中确定了一个简单的边缘情况,它应该可以工作但是失败了

尝试执行插入并移动到相同的索引路径({length = 2,path = 0 - 2})

我的操作是从[A,B] - > [C,B',A]开始.这是通过更新完成的:

  • 从索引0移动到2
  • 索引1的重新加载
  • 索引为0的插入

显然错误是错误的,插入索引不同于移动TO索引.

我设置了demo以确保这是一个UICollectionView问题,如果你想看到它的运行,这是我的代码:

@implementation ViewController {
  UICollectionView *_collection;
  NSArray *_values;
}

- (instancetype)init
{
  self = [super init];
  if (self) {
    UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
    _collection = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
    _collection.dataSource = self;
    _values = @[@1, @2];
    [_collection registerClass:[UICollectionViewCell class]
      forCellWithReuseIdentifier:@"reuse"];
    [self.view addSubview:_collection];
  }
  return self;
}

- (void)viewDidLoad {
  [super viewDidLoad];
  _collection.frame = self.view.bounds;

  double delayInSeconds = 2.0;
  dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
  dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    [self triggerBatchUpdate];
  });
}

- (void)triggerBatchUpdate {
  [_collection performBatchUpdates:^{
    _values = @[@4, @5, @1];
    [_collection insertItemsAtIndexPaths:@[[self index:0]]];
    [_collection moveItemAtIndexPath:[self index:0] toIndexPath:[self index:2]];

    // Works with this line
//    [_collection moveItemAtIndexPath:[self index:1] toIndexPath:[self index:1]];

    // Fails with this line
    [_collection reloadItemsAtIndexPaths:@[[self index:1]]];
  } completion:nil];
}

- (NSIndexPath *)index:(NSUInteger)ind {
  return [NSIndexPath indexPathForRow:ind inSection:0];
}

- (NSInteger)collectionView:(UICollectionView *)collectionView
     numberOfItemsInSection:(NSInteger)section {
  return _values.count;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
                  cellForItemAtIndexPath:(NSIndexPath *)indexPath {
  UICollectionViewCell *cell = [_collection dequeueReusableCellWithReuseIdentifier:@"reuse"
                                                                      forIndexPath:indexPath];
  cell.backgroundColor = [UIColor grayColor];
  return cell;
}


@end
Run Code Online (Sandbox Code Playgroud)

如果我使用代码的话这一事实

[_collection moveItemAtIndexPath:[self index:1] toIndexPath:[self index:1]];
Run Code Online (Sandbox Code Playgroud)

代替

[_collection reloadItemsAtIndexPaths:@[[self index:1]]];
Run Code Online (Sandbox Code Playgroud)

让我怀疑.这两个操作应该是等效的.

知道这里发生了什么吗?我认为这是一个UICollectionView错误吗?

编辑:另一个崩溃,结果与此有关:

尝试从同一索引路径执行删除和移动({length = 2,path = 0 - 5})

Pau*_*w11 7

它似乎确实是一个错误,虽然虽然文档performBatchUpdates:completion解释了插入和删除操作中索引的上下文,并且提到允许重载操作,但它没有详细说明重载操作中索引的上下文.

经过一些实验,似乎"在幕后"重新加载实现为删除和插入.这似乎导致一些问题,其中一些其他操作和重新加载索引之间存在重叠.

但是,我确实发现,使用显式删除和插入替换重新加载似乎有效,因此您可以使用:

- (void)triggerBatchUpdate {
    [_collection performBatchUpdates:^{
        _values = @[[UIColor blueColor], [UIColor yellowColor], [UIColor redColor]];
        [_collection moveItemAtIndexPath:[self index:0] toIndexPath:[self index:2]];
        [_collection insertItemsAtIndexPaths:@[[self index:0]]];

        [_collection deleteItemsAtIndexPaths:@[[self index:1]]];
        [_collection insertItemsAtIndexPaths:@[[self index:1]]];
    } completion:nil];
}
Run Code Online (Sandbox Code Playgroud)