I have a piece of code in an iPhone app, which removes all subviews from a UIView subclass. It looks like this:
NSArray* subViews = self.subviews;
for( UIView *aView in subViews ) {
[aView removeFromSuperview];
}
This works fine. In fact, I never really gave it much thought until I tried nearly the same thing in a Mac OS X app (from an NSView subclass):
NSArray* subViews = [self subviews];
for( NSView *aView in subViews ) {
[aView removeFromSuperview];
}
That totally doesn’t work. Specifically, at runtime, I get this:
*** Collection <NSCFArray: 0x1005208a0> was mutated while being enumerated.
I ended up doing it like so:
NSArray* subViews = [[self subviews] copy];
for( NSView *aView in subViews ) {
[aView removeFromSuperview];
}
[subViews release];
That's fine. What’s bugging me, though, is why does it work on the iPhone?
subviews is a copy property:
@property(nonatomic,readonly,copy) NSArray *subviews;
My first thought was, maybe @synthesize’d getters return a copy when the copy attribute is specified. The doc is clear on the semantics of copy for setters, but doesn’t appear to say either way for getters (or at least, it’s not apparent to me). And actually, doing a few tests of my own, this clearly does not seem to be the case. Which is good, I think returning a copy would be problematic, for a few reasons.
So the question is: how does the above code work on the iPhone? NSView is clearly returning a pointer to the actual array of subviews, and perhaps UIView isn’t. Perhaps it’s simply an implementation detail of UIView, and I shouldn’t get worked up about it.
Can anyone offer any insight?
This is a bug in -[NSView subviews]
. I could have sworn it was fixed for Snow Leopard, but can't find any evidence now.
Fortunately, there's a simpler way to remove all subviews:
[self setSubviews:[NSArray array]];
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With