UIView.subviews和[NSView子视图]之间的行为差​​异

时间:2011-01-12 03:49:44

标签: iphone cocoa macos uiview nsview

我在iPhone应用程序中有一段代码,它从UIView子类中删除所有子视图。它看起来像这样:

NSArray* subViews = self.subviews;
for( UIView *aView in subViews ) {
    [aView removeFromSuperview];
}

这很好用。事实上,在Mac OS X应用程序(来自NSView子类)中尝试几乎相同的东西之前,我从未真正考虑过它:

NSArray* subViews = [self subviews];
for( NSView *aView in subViews ) {
    [aView removeFromSuperview];
}

这完全不起作用。具体来说,在运行时,我得到了这个:

*** Collection <NSCFArray: 0x1005208a0> was mutated while being enumerated.

我最终这样做了:

NSArray* subViews = [[self subviews] copy];
for( NSView *aView in subViews ) {
    [aView removeFromSuperview];
}
[subViews release];

没关系。然而,令我烦恼的是,为什么它适用于iPhone呢?

子视图是一个复制属性:

@property(nonatomic,readonly,copy) NSArray *subviews;

我的第一个想法是,当指定copy属性时,@ synthesize'd getters可能会返回一个副本。 The doc对于setter的复制语义很清楚,但似乎没有对getter说两种方式(或者至少对我来说不明显)。实际上,做了我自己的一些测试,这显然不是这种情况。哪个好,我认为返回副本会有问题,原因有几个。

所以问题是:上面的代码如何在iPhone上运行? NSView显然返回了一个指向实际子视图数组的指针,也许UIView不是。也许它只是UIView的一个实现细节,我不应该对此有所了解。

任何人都可以提供任何见解吗?

3 个答案:

答案 0 :(得分:13)

这是-[NSView subviews]中的错误。我本可以发誓这是针对Snow Leopard的,但现在找不到任何证据。

幸运的是,有一种更简单的方法可以删除所有子视图:

[self setSubviews:[NSArray array]];

答案 1 :(得分:3)

更好地使用

while([self.subviews count] > 0){
    [[self.subviews objectAtindex:0] removeFromSuperview];
}

希望得到这个帮助。

答案 2 :(得分:2)

是的,这正是Apple实施它的方式。在mac上,子视图返回视图使用的实际(可变)数组,因此在添加或删除视图时不能使用快速枚举。如果要使用reverseObjectEnumerator,则可以使用。不要使用普通的枚举器,因为它可能会跳过子视图,因为它们会向上移动以替换已删除的子视图。然而,在iOS中,Apple似乎已经意识到这个问题并通过自动返回副本来修复它。属性声明仅描述了它的设置方式,但apple也选择复制getter。