Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/119.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios UICollectionView批处理更新边缘案例失败_Ios_Objective C_Uicollectionview_Uikit_Performbatchupdates - Fatal编程技术网

Ios UICollectionView批处理更新边缘案例失败

Ios UICollectionView批处理更新边缘案例失败,ios,objective-c,uicollectionview,uikit,performbatchupdates,Ios,Objective C,Uicollectionview,Uikit,Performbatchupdates,我在UICollectionView的batchUpdate操作中发现了一个简单的边缘情况,该操作应该可以工作,但在 尝试执行插入并移动到同一索引路径({length=2,path=0-2}) 我的操作是从[A,B]-->[C,B',A]开始。这是通过以下更新完成的: 从索引0移动到2 重新加载索引1 在索引0处插入 显然错误是错误的,插入索引与移动到索引不同 我设置了演示,以确保这是一个UICollectionView问题,如果您希望看到它的实际运行,请参阅我的代码: @implement

我在UICollectionView的batchUpdate操作中发现了一个简单的边缘情况,该操作应该可以工作,但在

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

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

  • 从索引0移动到2
  • 重新加载索引1
  • 在索引0处插入
显然错误是错误的,插入索引与移动到索引不同

我设置了演示,以确保这是一个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
如果我使用

[_collection moveItemAtIndexPath:[self index:1] toIndexPath:[self index:1]];
而不是

[_collection reloadItemsAtIndexPaths:@[[self index:1]]];
让我怀疑。这两个操作应该是等效的

知道这是怎么回事吗?我相信这是UICollectionView错误吗

编辑: 另一个与此相关的崩溃:

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


虽然
performbatchudates:completion
的文档解释了insert和delete操作中索引的上下文,并提到允许重新加载操作,但它没有详细说明重新加载操作中索引的上下文,这似乎是一个bug

经过一些实验,似乎“隐藏”的重新加载被实现为删除和插入。这似乎会导致其他操作与重新加载索引之间存在重叠的问题

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

- (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];
}

如果在移动之前执行插入操作,会怎么样?从0移动到2对只包含2个项的集合无效。不改变任何内容,也不应该改变任何内容。在batchUpdate中执行操作的顺序并不重要,它们是按照apple定义的顺序执行的(先删除,然后插入,然后移动)。“从索引移动”对应于其处于原始状态的索引,“到索引”相对于最终状态。它看起来像一个bug。仅供参考,使用
[\u集合moveItemAtIndexPath:[自索引:1]到IndexPath:[自索引:1]]实际上不起作用,因为第二个单元格没有重新加载。我使用了颜色而不是数字,因此您可以看到发生了什么:只有当我将重新加载移动到完成块时,它才会起作用。如果我放弃移动,离开插入,然后尝试重新加载索引2处的项目,我会遇到一个错误,即当只有2个项目时,我尝试删除项目2。重新加载似乎转换为删除和插入,这会导致索引在批处理过程中发生更改的问题。如果我将重载替换为索引1的离散删除,然后为索引1插入,那么效果会很好!我完全错误地认为我的移动到了自身(不确定这是从哪里来的,我想知道它是否曾经是真的?)我想你是对的,从重新加载到删除和插入的转换是完全有意义的。有一个非常类似的崩溃,我无法通过删除和移动复制,这加强了你的理论。用删除和插入替换重新加载似乎效果不错:)你可以写一个答案来解释这一切,我会接受的。如果你不愿意,那很好,我会为子孙后代做的。