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
。至于原因:很简单,您不应该在枚举过程中更改数组顺序/值,如果更改,也会影响循环值,请在执行之前复制一份