Ios 删除数组枚举中的对象

Ios 删除数组枚举中的对象,ios,objective-c,Ios,Objective C,有时有效,有时崩溃,为什么?删除后,对象不正确。因此,请复制为: [array enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { if (condition) { [array removeObject:obj]; } }]; 删除后,对象不正确。因此,请复制为: [array enumerateObjectsUsingBlock:^(id

有时有效,有时崩溃,为什么?

删除后,对象不正确。因此,请复制为:

[array enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
    if (condition) {
        [array removeObject:obj];
    }
}];

删除后,对象不正确。因此,请复制为:

[array enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
    if (condition) {
        [array removeObject:obj];
    }
}];

这是不安全的方式。我不太了解这种语言的内部执行,顺便说一句,我认为当你移除对象时,数组的大小就会减小,当你到达数组的最后一个元素时就会出错。 我认为在枚举块中,不允许更改数组。其他语言也有同样的问题。 您可以在此url中获得更多信息。
这是一种不安全的方式。我不太了解这种语言的内部执行,顺便说一句,我认为当你移除对象时,数组的大小就会减小,当你到达数组的最后一个元素时就会出错。 我认为在枚举块中,不允许更改数组。其他语言也有同样的问题。 您可以在此url中获得更多信息。

想象一下,如果您在苹果公司工作并被要求添加此代码,您将如何为
-EnumerateObjectsSusingBlock:
编写代码。它可能看起来像:

[array enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
    if (condition) {
  int counter =  [array indexOfObject:obj];
    [array removeObjectAtIndex:counter];
    }
}];
myBlock(A,0)
更改为:

0: A
1: B
2: C
3: D
现在执行
x++
,因此下一个调用是
myBlock(C,1)
——您已经看到“B”现在被跳过,最初在索引2处的项被第二次删除(而不是索引1处的项)。删除后,我们再次循环,数组如下所示:

0: B
1: C
2: D
因此,当
-EnumerateObjectsSusingBlock:
尝试删除索引2处的项时,它会从数组的末尾运行,您会遇到崩溃

简而言之,
-EnumerateObjectsSusingBlock:
的文档没有说明在迭代数组时可以修改数组,并且块无法告诉
-EnumerateObjectsSusingBlock:
中的循环代码它刚刚删除了一个对象,因此您不能依赖该工作

(您可以自己尝试一下……将此版本的EnumerateObjectsSusingBlock:重命名为MyEnumerateObjectsSusingBlock:,在NSArray上的一个类别中声明它,并使用类似以下程序在调试器中逐步执行它:
[myArray MyEnumerateObjectsSusingBlock:^(id _nonnullobj,nsuiger idx,BOOL*.\u Nonnull stop){[myArray removeObject:obj];}];

如果您希望从数组中删除项,有几种解决方法。首先,您可以复制数组,循环该数组,并从原始数组中删除对象。另一个选项是在数组上向后迭代,这意味着早期项的索引不会更改(请尝试修改上面的
-enumerateObjectsUsingBlock:
版本,并观察调试器中发生的情况)


还有一种方法是编写自己的方法来过滤数组。给它一个块,如果要保留该对象,该块将返回YES,如果不应该,则返回NO。然后在原始数组上循环,对每个项目调用块,并创建一个新数组,向其中添加块返回YES的所有对象。

想象一下,如果您在Apple工作并被要求添加此项,您将如何为
-EnumerateObjectsSusingBlock:
编写代码。它可能看起来像:

[array enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
    if (condition) {
  int counter =  [array indexOfObject:obj];
    [array removeObjectAtIndex:counter];
    }
}];
myBlock(A,0)
更改为:

0: A
1: B
2: C
3: D
现在执行
x++
,因此下一个调用是
myBlock(C,1)
——您已经看到“B”现在被跳过,最初在索引2处的项被第二次删除(而不是索引1处的项)。删除后,我们再次循环,数组如下所示:

0: B
1: C
2: D
因此,当
-EnumerateObjectsSusingBlock:
尝试删除索引2处的项时,它会从数组的末尾运行,您会遇到崩溃

简而言之,
-EnumerateObjectsSusingBlock:
的文档没有说明在迭代数组时可以修改数组,并且块无法告诉
-EnumerateObjectsSusingBlock:
中的循环代码它刚刚删除了一个对象,因此您不能依赖该工作

(您可以自己尝试一下……将此版本的EnumerateObjectsSusingBlock:重命名为MyEnumerateObjectsSusingBlock:,在NSArray上的一个类别中声明它,并使用类似以下程序在调试器中逐步执行它:
[myArray MyEnumerateObjectsSusingBlock:^(id _nonnullobj,nsuiger idx,BOOL*.\u Nonnull stop){[myArray removeObject:obj];}];

如果您希望从数组中删除项,有几种解决方法。首先,您可以复制数组,循环该数组,并从原始数组中删除对象。另一个选项是在数组上向后迭代,这意味着早期项的索引不会更改(请尝试修改上面的
-enumerateObjectsUsingBlock:
版本,并观察调试器中发生的情况)


还有一种方法是编写自己的方法来过滤数组。给它一个块,如果要保留该对象,该块将返回YES,如果不应该,则返回NO。然后在原始数组上循环,调用每个项上的块,并创建一个新数组,向其中添加块返回YES的所有对象。

对此,您可能应该使用
filteradarayusingpredicate
。至于原因:很简单,您不应该在枚举过程中更改数组顺序/值,如果更改,也会影响循环值,请在执行之前复制一份this@cleverIdiot-前面的评论给出了答案。不幸的是,你目前接受的答案是错误的。您可能希望邀请一位评论员添加答案,以便您可以接受。但我需要删除它并重新加载我的表视图您可能应该使用
filteredarrayingpredicate
。至于原因:很简单,您不应该在枚举过程中更改数组顺序/值,如果更改,也会影响循环值,请在执行之前复制一份