2009-07-01 7 views
13

Si la clase A usa la clase B y la clase A es delegada de la clase B, está bien si el delegado se establece en cero en la clase B dealloc ? He visto código que generalmente restablece el delegado a nulo dentro del dealloc de la clase A pero no estaba seguro de la diferencia real que lo hace de una forma u otra.Debería establecer el delegado a cero en la clase usando el delegado o en la clase

p. Ej. Esta es la forma habitual:

// somewhere in class A 

- (void) someFunc { 
    self.b = [[B alloc] init]; 
    self.b.delegate = self; 
} 

- (void) dealloc { 
    self.b.delegate = nil; 
    [self.b release]; 
} 
+2

'self.b = [[B alloc] init];' nunca debe usar 'self'on LHS si está utilizando' alloc' en RHS si se retiene '@ property' for' b'. Justed quería agregar. – thesummersign

+0

@geekay, ¿por qué es eso? –

+0

esto fue durante no-arco – thesummersign

Respuesta

15

Sí, debe establecer la propiedad delegado del ClassB a cero en dealloc de classA.

No es un problema de administración de memoria, porque las propiedades de delegado deben marcarse assign, not reten, para evitar retener ciclos (de lo contrario, nunca se llamará a dealloc). El problema es que, de lo contrario, la clase B podría enviar un mensaje de clase A después de su publicación.

Por ejemplo, si classB tiene una llamada de revisión para decir "estar oculto", y la clase B se lanza justo después de la clase A, enviaría un mensaje a la clase A ya desasignada causando un bloqueo.

Y recuerde, no siempre puede garantizar el orden de atención, especialmente si se lanzan automáticamente.

Así que sí, nula la propiedad de delegado en dealloc de la clase A.

+1

+1 Un buen punto sobre B, posiblemente mensajería A. Es más probable en un escenario de subprocesos múltiples, pero nunca se sabe. Esta es una gran aplicación para las referencias __weak si está usando GC. Creo que los delegados siempre deben ser __weak en el nuevo código. –

+0

yup me mordieron esto en una aplicación multiproceso – marchinram

8

Por lo que yo sé, sus mejores prácticas a (asignar) un delegado, tal que evite referencias circulares en retener los recuentos para situaciones como esta. Si se ha configurado correctamente la propiedad, es decir:

@property (assign) id<BDelegate> delegate; 

Usted no debería tener que realizar ninguna gestión de memoria en el dealloc, como el recuento de retener no se golpea cuando se llama a sí mismo self.b.delegate = ; - a diferencia de usar (retener) o (copiar)

¿Tiene sentido? Estaría bien establecer el delegado a cero, pero ¿cuál es el punto?

+0

+1 Eso es correcto, los delegados casi nunca deben conservarse. Esa es una causa clásica de retención de ciclos, ya que el delegado por lo general conserva el objeto delegado. –

+3

Hay un punto en configurar el delegado en nil porque si el cliente intenta llamar a un objeto delegado que ya no existe, no se bloqueará ya que está establecido en nil. – Boon

+0

Está desasignando la clase que contiene el delegado ... está eliminando la instanciación de la clase de la memoria en ese punto, obtendrá un error de acceso a memoria si realiza alguna acción en el objeto, mucho menos consulte a su delegado. A menos que me falta algo aquí ... – Josh

5

En primer lugar, algunas observaciones ...

  1. Te has olvidado de llamar [super dealloc] al final de su propio método dealloc.
  2. Dado que 'a' creó 'b', y si ningún otro objeto ha retenido 'b', no tiene sentido marcar al delegado en -dealloc, ya que 'b' está a punto de destruirse de todos modos. Si es posible que otros objetos tengan una referencia a 'b' (lo que significa que podría sobrevivir a 'a'), configure el delegado en nil.
  3. El objeto 'b' debe ser el encargado de cuidar a su delegado en su propio -dealloc si es necesario. (En general, el delegador no retiene al delegado).
  4. Evite usar propiedades en los métodos -init ... y -dealloc - Apple lo desalienta, y por una buena razón. (No solo puede tener efectos secundarios inesperados, sino que también puede causar problemas más desagradables y atropellados).
  5. Usar propiedades (a través de la sintaxis de punto) cuando no necesita agregar trabajo extra de manera invisible. Por ejemplo, self.b.delegate = self es equivalente a [[self getB] setDelegate:self] - es solo el azúcar sintáctico el que hace que parezca que estás accediendo directamente al ivar, pero en realidad no lo estás.
  6. Usar propiedades sin comprender lo que hacen puede ocasionar problemas. Si self.b retiene el valor (la propiedad está configurada para "asignar"), tiene una pérdida de memoria en sus manos.

Así es como yo probablemente escribirlo:

- (void) someFunc { 
    b = [[B alloc] init]; 
    b.delegate = self; // or [b setDelegate:self]; 
} 

- (void) dealloc { 
    b.delegate = nil; 
    [b release]; 
    [super dealloc]; 
} 
Cuestiones relacionadas