UIView.subviews 和 [NSView subviews] 之间的行为差异
Posted
技术标签:
【中文标题】UIView.subviews 和 [NSView subviews] 之间的行为差异【英文标题】:Behavior difference between UIView.subviews and [NSView subviews] 【发布时间】:2011-01-12 03:49:44 【问题描述】:我在 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 的一个实现细节,我不应该为此烦恼。
谁能提供任何见解?
【问题讨论】:
【参考方案1】:这是-[NSView subviews]
中的一个错误。我可以发誓这是为雪豹修复的,但现在找不到任何证据。
幸运的是,有一种更简单的方法可以删除所有子视图:
[self setSubviews:[NSArray array]];
【讨论】:
这几乎不是一个错误@Mike。它只是 [someNSView subviews] 返回指向子视图数组的指针,而 [someUIView subviews] 返回该数组的副本。这就是它在 ios 上运行良好的原因。【参考方案2】:更好的使用
while([self.subviews count] > 0)
[[self.subviews objectAtindex:0] removeFromSuperview];
希望对您有所帮助。
【讨论】:
【参考方案3】:是的,这正是 Apple 实现它的方式。在 Mac 上,子视图返回视图使用的实际(可变)数组,因此在添加或删除视图时不能使用快速枚举。如果你想使用 reverseObjectEnumerator,你也许可以。不要使用普通的枚举器,因为它可能会跳过子视图,因为它们被向上移动以替换那些被移除的子视图。然而,在 iOS 中,Apple 似乎已经意识到了这个问题,并通过自动返回副本来修复它。属性声明只描述了它是如何设置的,但苹果也选择复制getter。
【讨论】:
以上是关于UIView.subviews 和 [NSView subviews] 之间的行为差异的主要内容,如果未能解决你的问题,请参考以下文章