我有一个充满按钮的UIView * buttonView。我需要更新我的列表并重新填充我的buttonView。我实施了:
if ([[self.buttonView.subviews objectAtIndex:i] isKindOfClass:[UIButon class]]
[[self.buttonView.subviews objectAtIndex:i] removeFromSuperview];
但它失败了,它不会删除所有按钮(我的测试有8个按钮,它每隔一个按钮删除一次: - ?)
然后我尝试了:
for(UIView *subview in self.buttonView.subviews)
{
if([subview isKindOfClass:[UIButton class]])
[subview removeFromSuperview];
}
它完美无缺。
这两个循环不应该完成同样的事情吗?
我猜我还有一些我不知道的关于快速枚举的内容可以解释这一点吗?
答案 0 :(得分:5)
你的根本问题是你在迭代时改变了一个集合。如果您确实需要这样做,您可能需要考虑向后迭代(使用-reverseObjectEnumerator
或使用-enumerateObjectsWithOptions:usingBlock:
反向选项)。或者,您可以在迭代之前创建数组的副本。
快速枚举的原因可能是由于调用-subviews
返回子视图数组的某种常量副本。这实际上可以在你的第一种情况下使用,只需调用-subviews
一次并重新使用结果,但这会引入对实现细节的依赖,我强烈建议避免它。如果你需要一个数组的常量副本,你应该自己制作一个。
解决案例1的最快解决方案是:
NSArray *subviews = [NSArray arrayWithArray:self.buttonView.subviews];
// now enumerate using the subviews array directly instead of calling self.buttonView.subviews
对于快速枚举的情况,您可能希望将其重写为
for (UIView *subview in [NSArray arrayWithArray:self.buttonView.subviews]) {
// ...
}
第三种选择是切换到基于块的枚举并反向进行。如果你能做到这一点,这实际上将是最有效的选择:
[self.buttonView.subviews enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(UIView *subview, NSUInteger idx, BOOL *stop) {
if ([subview isKindOfClass:[UIButton class]]) {
[subview removeFromSuperview];
}
}];
答案 1 :(得分:3)
如果你反向运行它,你的for循环就会起作用(从最高索引开始并在i > 0
循环时)。编写for
循环的方式,每次删除对象时,索引都会发生变化。编写枚举的方式,可以安全地删除枚举中的对象,或者预先返回所有对象,这样就不会有任何跳过任何元素的机会。
答案 2 :(得分:2)
我不相信你可以修改你所枚举的收藏品,所以要小心。看起来好像处理变化就好了,它会遍历每个项目(与for循环不同)。
在第一种情况下,它不起作用,因为一旦你删除索引0,其他东西变成索引0,但你已经转移到索引1.你可以通过减少循环变量来修复它,如果删除成功,以便循环将其递增到其先前的值:
if ([[self.buttonView.subviews objectAtIndex:i] isKindOfClass:[UIButton class]]) {
[[self.buttonView.subviews objectAtIndex:i] removeFromSuperview];
--i;
}
for循环会发生什么:
1,2,3,4,5,6,7,8
并删除第一项(1)
2,3,4,5,6,7,8
并删除第二项(3)
2,4,5,6,7,8
并删除第三项(5)
2,4,6,7,8
并删除第四项(7)。
2,4,6,8
你在索引5上,这比长度大,所以你已经完成了。
答案 3 :(得分:0)
就像其他人说的那样,你的主要问题是在迭代它时修改一个可变数组。相反,您可以找到所有按钮作为buttonView的子视图,并使它们执行removeFromSuperview。
id buttonClassTest = ^(UIView * subview, NSUInteger idx, BOOL *stop){
return [subview isKindOfClass:[UIButton class]];
};
NSIndexSet * indexes = [self.buttonView.subviews indexesOfObjectsPassingTest:buttonClassTest];
NSArray * buttons = [self.buttonView.subviews objectsAtIndexes:indexes];
[buttons makeObjectsPerformSelector:@selector(removeFromSuperview)];