2012-03-17 13 views
7

Estoy agregando dos subvistas, que están almacenadas por propiedades, a mi vista. Al agregar las subvistas a mi vista, las subViews se desasignan aparentemente después de llamar a mi método setup. El resultado final es que las vistas nunca se muestran. Ahora, si cambio mis propiedades a strong en lugar de weak, conservo una referencia a las vistas y ahora se muestran en la pantalla. Entonces, ¿qué está pasando aquí? ¿Por qué el addSubview: y el insertSubview: no conservan las subvistas? Ver el código de abajo:¿Por qué addSubview no conserva la vista?

por cierto, estoy usando IOS5 con ARC (de ahí el material fuerte y débil)

#import "NoteView.h" 
@interface NoteView() <UITextViewDelegate> 
@property (weak, nonatomic) HorizontalLineView *horizontalLineView; // custom subclass of UIView that all it does is draw horizontal lines 
@property (weak, nonatomic) UITextView *textView; 
@end 

@implementation NoteView 
@synthesize horizontalLineView = _horizontalLineView; 
@synthesize textView = _textView; 

#define LEFT_MARGIN 20 
- (void)setup 
{ 
    // Create the subviews and set the frames 
    self.horizontalLineView = [[HorizontalLineView alloc] initWithFrame:self.frame]; 
    CGRect textViewFrame = CGRectMake(LEFT_MARGIN, 0, self.frame.size.width, self.frame.size.height); 
    self.textView = [[UITextView alloc] initWithFrame:textViewFrame]; 


    // some addition setup stuff that I didn't include in this question... 

    // Finally, add the subviews to the view 
    [self addSubview:self.textView]; 
    [self insertSubview:self.horizontalLineView atIndex:0]; 
} 

- (void)awakeFromNib 
{ 
    [super awakeFromNib]; 

    [self setup]; 
} 

- (id)initWithFrame:(CGRect)frame 
{ 
    self = [super initWithFrame:frame]; 
    if (self) { 
     // Initialization code 
     [self setup]; 
    } 
    return self; 
} 
+0

¿Cómo va a crear la instancia de NoteView? ver de control está llegando en la configuración .. –

+0

Estoy creando la instancia de NoteView agregándola a un controlador de vista en un guión gráfico. –

+0

¿Está su clase especificada en Xib como NoteView –

Respuesta

21

Aquí hay una línea de código:

self.horizontalLineView = [[HorizontalLineView alloc] initWithFrame:self.frame]; 

Recordemos que la propiedad horizontalLineView es débil. Veamos lo que realmente sucede en esa línea, con el código adicional que genera ARC. En primer lugar, se envían los métodos alloc y initWithFrame:, volviendo una fuerte referencia:

id temp = [[HorizontalLineView alloc] initWithFrame:self.frame]; 

En este punto, el objeto HorizontalLineView tiene una cuenta de retención de 1. A continuación, ya que utiliza de sintaxis con punto para establecer la propiedad horizontalLineView , el compilador genera código para enviar el método setHorizontalLineView: al self, pasando temp como parámetro. Dado que la propiedad HorizontalLineView se declara weak, el método de selección hace esto:

objc_storeWeak(&self->_horizontalLineView, temp); 

que establece self->_horizontalLineView igual a temp, y pone &self->_horizontalLineView en la lista del objeto de referencias débiles. Pero hace no incrementa el conteo retenido del objeto HorizontalLineView.

Por último, ya que la variable temp ya no es necesaria, el compilador genera el siguiente:

[temp release]; 

que baja retener recuento del objeto HorizontalLineView a cero, por lo que desasigna el objeto. Durante la desasignación, recorre la lista de referencias débiles y establece cada una en nil. Entonces self->_horizontalLineView se convierte en nil.

La manera de solucionar este problema es hacer que el temp explícitas de variables, por lo que puede extender su vida útil hasta después de haber añadido el objeto HorizontalLineView a su supervista, que lo retiene:

HorizontalLineView *hlv = [[HorizontalLineView alloc] initWithFrame:self.frame]; 
self.horizontalLineView = hlv; 
// ... 
[self insertSubview:hlv atIndex:0]; 
+2

Guau, ¡tienes toda la razón! Este es el tipo exacto de explicación que esperaba sobre lo que está sucediendo detrás de la escena. ¿No parece extraño que tengas que pasar por el paso adicional de crear una variable explícita? En cualquier caso, gracias por la ayuda! –

+0

Descubrí que es suficiente simplemente introducir una variable de temperatura, no necesita usarla en la llamada a 'insertSubview'. Entonces podría usar '[self insertSubview: self.horizontalLineView atIndex: 0];' y aún funciona. Esto me parece contrario a la intuición. ¿Puedes explicar este comportamiento? –

3

débil no debe ser utilizado a menos que en los casos en que conservan un padre-hijo ciclo se formado (el padre mantiene una referencia al niño, el niño mantiene una referencia al padre, por lo que ninguno de los dos se trata). Strong es el equivalente de ARC de retener (ahora no válido en ARC) y mantiene un puntero estable al objeto durante un período de tiempo mucho más largo que una referencia débil, por lo que addSubview realmente funciona en lugar de darle algún tipo de error.

¿Por qué es addSubview: y insertSubview: no conserva las subvistas?

¿Alguna vez ha tratado de llamar a retener en un objeto nulo? Sip, sigue siendo nulo. Su referencia débil no es mantener el objeto UIView lo suficientemente largo como para 'retener llamadas' con éxito en el objeto.

+0

? ¿Por qué se bloqueará? –

+0

Supongo que enviar retener a una instancia desasignada ... – CodaFi

+0

Quiero decir que veo lo que dice acerca de cómo las vistas pueden no mantenerse el tiempo suficiente para ser retenidas, pero el método de instalación debe llamarse después de que la vista (principal) instanciado. Entonces, cuando agrego mis subvistas a la jerarquía de vistas, quedan retenidas, ¿verdad? Así que supongo que todavía estoy confundido aquí. ¿Qué me estoy perdiendo? –

0

Trate de usar esto en su lugar:

@property (nonatomic, retain) 
+0

Conservar no es válido en arco, y él estaba pidiendo una explicación. – CodaFi

+0

@CodaFi, retener propiedad es perfectamente válida bajo ARC. –

Cuestiones relacionadas