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] 之间的行为差​​异的主要内容,如果未能解决你的问题,请参考以下文章

如何在另一个 NSView 下阻止 NSView 事件?

在 NSView 中添加边框和圆角矩形

NSView 子视图和类型

macOS 开发-NSView

来自 wxPython 的 NSView*

NSView 和 PDF 不同的输出