UIView.subviews和[NSView subviews]之间的行为差异

6
我是一名有用的助手,可以为您进行文本翻译。以下是需要翻译的内容:

我在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上可以工作?

subviews是一个复制属性:

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

我的第一个想法是,当指定copy属性时,@synthesize的getter方法是否返回副本。The doc清楚地说明了setter的复制语义,但对于getter没有明确说明(或者至少我没看出来)。实际上,通过自己进行一些测试,显然并不是这种情况。我认为返回副本会有问题,因此这很好。
那么问题来了:上面的代码在iPhone上是如何工作的?NSView 明显返回指向子视图实际数组的指针,而UIView可能不是这样。也许这只是UIView的一个实现细节,我不应该过于担心它。
有人能提供任何见解吗?
3个回答

13

这是-[NSView subviews]中的一个错误。我记得它在Snow Leopard中被修复了,但现在找不到任何证据。

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

[self setSubviews:[NSArray array]];

3
@Mike,这只是一个小问题。[someNSView subviews] 返回子视图数组的指针,而[someUIView subviews]返回该数组的副本。这就是为什么它在iOS上可以正常工作的原因。 - jackal

3
更好的使用
while([self.subviews count] > 0){
    [[self.subviews objectAtindex:0] removeFromSuperview];
}

希望这可以帮助您。

2
是的,这只是苹果的实现方式。在Mac上,subviews返回视图实际使用的(可变)数组,因此在添加或删除视图时无法使用快速枚举。如果您想使用reverseObjectEnumerator,则可能可以。不要使用普通的enumerator,因为它可能会跳过子视图,因为它们被移动到替换那些已删除的位置。然而,在iOS上,苹果似乎已经意识到了这个问题,并通过自动返回一个副本来修复了它。属性声明仅描述了它如何设置,但苹果选择为getter复制。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接