2011-01-12 16 views
7

Tengo un fragmento de código en una aplicación de iPhone, que elimina todas las subvistas de una subclase de UIView. Se ve así:Diferencia de comportamiento entre UIView.subviews y [NSView subviews]

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

Esto funciona bien. De hecho, yo nunca le di mucha importancia hasta que probé casi lo mismo en una aplicación de Mac OS X (de una subclase NSView):

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

que totalmente no funciona. En concreto, en tiempo de ejecución, me sale esto:

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

acabé haciéndolo de este modo:

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

Eso está bien. Lo que me molesta, sin embargo, es ¿por qué funciona en el iPhone?

subvistas es una propiedad de copia:

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

Mi primer pensamiento fue, tal vez captadores @ synthesize'd devolver una copia cuando se especifica el atributo de copia. The doc es claro en la semántica de copy para setters, pero no parece decir de ninguna manera para getters (o al menos, no es aparente para mí). Y, de hecho, haciendo algunas pruebas por mi cuenta, esto claramente no parece ser el caso. Lo cual es bueno, creo que devolver una copia sería problemático, por algunas razones.

Entonces la pregunta es: ¿cómo funciona el código anterior en el iPhone? NSView claramente está devolviendo un puntero al conjunto real de subvistas, y quizás UIView no lo esté. Quizás es simplemente un detalle de implementación de UIView, y no debería preocuparme por ello.

¿Alguien puede ofrecer alguna idea?

Respuesta

13

Esto es un error en -[NSView subviews]. Podría haber jurado que se arregló para Snow Leopard, pero ahora no puedo encontrar ninguna evidencia.

Afortunadamente, hay una manera más sencilla de eliminar todos los subvistas:

[self setSubviews:[NSArray array]]; 
+3

Es apenas un @ Mike fallo. Es solo [algunas subvistas de NSView] devuelve el puntero a la matriz de subvistas, mientras que [algunas subvistas de IVIV] devuelve la copia de esa matriz. Es por eso que funciona bien en iOS. – jackal

2

Sí, así es como Apple lo implementó. En mac, las subvistas devuelven la matriz real (mutable) utilizada por la vista, por lo que no puede usar la enumeración rápida al agregar o eliminar vistas. Si desea utilizar el reverseObjectEnumerator, es posible que pueda hacerlo. No use el enumerador normal porque puede omitir las subvistas a medida que se mueven hacia arriba para reemplazar las enumeradas. Sin embargo, en iOS, Apple parece haberse dado cuenta de este problema y lo solucionó devolviendo una copia automáticamente. La declaración de propiedad solo describe cómo se establece, pero Apple eligió copiar también para el getter.

3

Mejor uso

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

Esperanza esta ayuda.