枚举数组时删除数组中的元素

时间:2019-06-10 13:41:51

标签: objective-c

例如:

NSMutableArray *array = [NSMutableArray arrayWithObjects:@"A", @"B", @"C", nil];
[array enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
    if ([obj isEqualToString:@"A"]) {
        [array removeObject:obj];
    }
}];
NSLog(@"%@", array);

控制台打印B,C

但是:

NSMutableArray *array = [NSMutableArray arrayWithObjects:@"A", @"B", @"C", nil];
[array enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
    if ([obj isEqualToString:@"A"]) {
        [array removeObject:obj];
    } else if ([obj isEqualToString:@"B"]) {
        [array removeObject:obj];
    }
}];
NSLog(@"%@", array);

控制台打印B,C

为什么“ B,C”不是“ C”?

枚举时删除数组中的obj会发生什么?

5 个答案:

答案 0 :(得分:1)

在第一次迭代中,您将获得索引零值'A'。如果条件满足。然后删除A。现在,第二次迭代索引为1。索引为1的对象是C。因为您删除了“ A”,所以B移至零索引。因此,在第二次迭代中,它检查C而不是B。这就是为什么不删除B的原因。

答案 1 :(得分:1)

枚举器按顺序在对象上运行。首次输入块obj = array[0]表示obj = @"A"。然后array[0]被删除。下次输入块obj = array[1]时,但array现在是@[@"B", @"C"],所以obj = @"C"。您永远不会在@"B"上进行迭代,因此无法将其删除。

通常,交替数组在遍历它们时非常危险,因此不建议使用。还有其他方法可以从数组中删除对象。

答案 2 :(得分:1)

可能的方法是迭代数组并存储要删除的索引

答案 3 :(得分:1)

在其他答案中正确提到了代码不起作用的原因,索引被修改了。

如果要在枚举数组时删除对象,则必须枚举始终向后

在删除索引1处的项目后,索引0保持不变。

NSMutableArray *array = [NSMutableArray arrayWithObjects:@"A", @"B", @"C", nil];
[array enumerateObjectsWithOptions: NSEnumerationReverse usingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
    if ([obj isEqualToString:@"A"]) {
        [array removeObject:obj];
    } else if ([obj isEqualToString:@"B"]) {
        [array removeObject:obj];
    }
}];
NSLog(@"%@", array);

答案 4 :(得分:0)

更改您要迭代的集合有时很难理解。有充分的理由避免它,即使您的情况也很简单。 (但是,当您删除数组的其他元素时,这些解决方案会很快中断。)

有一些通用的解决方案:

A。遍历副本

NSMutableArray *array = [NSMutableArray arrayWithObjects:@"A", @"B", @"C", nil];
NSArray *iterationArray = [array copy];
[iterationArray enumerateObjectsWithOptions: NSEnumerationReverse usingBlock:
^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  if ([obj isEqualToString:@"A"]) {
    [array removeObject:obj];
  } else if ([obj isEqualToString:@"B"]) {
    [array removeObject:obj];
  }
}];

B。存储要删除的对象

NSMutableArray *array = [NSMutableArray arrayWithObjects:@"A", @"B", @"C", nil];
NSMutableArray *itemsToRemove = [NSMutableArray new];
[array enumerateObjectsWithOptions: NSEnumerationReverse usingBlock:
^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  if ([obj isEqualToString:@"A"]) {
    [itemsToRemove addObject:obj];
  } else if ([obj isEqualToString:@"B"]) {
    [itemsToRemove addObject:obj];
  }
}];
[array remveObjects:itemsToRemove];

所有这些方法包括您的方法可能会导致意外结果,因为-removeObject:会删除对象在数组本身中出现的所有,这意味着删除所有与arg相等的对象,包括不相同的对象。

C。删除具有该索引的对象

如果您要使用索引进行迭代(或者可以轻松地建立索引),则存储索引然后再使用该索引删除将更加有效。这使您有机会在相等和相同的对象之间进行区分。就您而言

NSMutableArray *array = [NSMutableArray arrayWithObjects:@"A", @"B", @"C", nil];
NSMutableIndexSet *itemsToRemove = [NSMutableIndexSet new];
__block NSUInteger index=0;
[array enumerateObjectsWithOptions: NSEnumerationReverse usingBlock:
^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) 
{
  if ([obj isEqualToString:@"A"]) 
  {
    [itemsToRemove addIndex:index];
  } else if ([obj isEqualToString:@"B"]) {
    [itemsToRemove addIndex:index];
  }
  index++;
}];
[array removeObjectsAtIndexes:itemsToRemove];
NSLog(@"%@", array);