iphone - Se establece en nil en viewDidUnload, pero se libera en dealloc
objective-c cocoa-touch (2)
Primero lo primero, la línea
[self.label release];
es absolutamente incorrecto, independientemente de dónde lo llame. Nunca debe llamar- -release
sobre los resultados del acceso a la propiedad. Esto es exactamente lo mismo que escribir el [[self label] release]
, que espero que pueda reconocer como incorrecto.
La muestra de tu código debe ser similar a la siguiente:
- (void)viewDidUnload {
self.label = nil;
[super viewDidUnload];
}
- (void)dealloc {
[label release];
[super dealloc];
}
Si miramos -viewDidUnload
primero, es bastante simple. self.label = nil;
es correcto. Del mismo modo correcto sería [self setLabel:nil];
. Y aunque no es tan bueno, también sería aceptable escribir [label release], label = nil;
. Esta última forma no es tan buena porque evita el método setter, que puede estar haciendo más cosas que simplemente liberar la propiedad (por ejemplo, puede mantener el estado interno que se preocupa por el valor de la propiedad). También pasa por alto las notificaciones de KVO.
La verdadera pregunta aquí es qué haces en -dealloc
. Mucha gente sugiere que está perfectamente bien decir self.label = nil;
, y hablando en términos prácticos, esto funcionará la mayor parte del tiempo. El problema es que el resto del tiempo provocará errores sutiles. Hay dos cosas que puede hacer la llamada al colocador. La primera es que puede causar efectos secundarios en su clase si el método setter se implementa manualmente (incluso si no está implementando el setter usted mismo, una subclase podría). El segundo es que puede transmitir notificaciones KVO. Ninguna de estas cosas se desea cuando estás en -dealloc
. Al liberar el ivar directamente, como en [label release];
, evita los posibles efectos secundarios y las notificaciones de KVO.
He estado leyendo todo el día acerca de por qué las vistas deberían establecerse como nulas en viewDidUnload y publicadas en dealloc. Todos los artículos siguen repitiendo lo mismo. Sí, sé que las instrucciones detrás de la escena son diferentes, pero ¿cuáles son las diferencias prácticas?
var = nil
- Si var es una propiedad retenida, recupere la memoria a la que apunta el objeto antiguo var.
- Establecer var a nil.
[var release]
- Reclamar los puntos var de memoria a.
- var ahora apunta a nada, lo que es equivalente a nada
Para mí, ambas formas de reclamar la memoria tienen el mismo resultado final. Entonces, ¿por qué uno sobre el otro? Cada libro me dice que establezca nulo en viewDidUnload
y release in dealloc
. Alguien debería señalar las cosas malas que sucederían si se publicara una vista en viewDidUnload
y nilled en dealloc
.
.marido
#import <UIKit/UIKit.h>
@interface DisclosureDetailController : UIViewController {
UILabel* label;
}
@property (nonatomic, retain) IBOutlet UILabel* label;
@end
.metro
#import "DisclosureDetailController.h"
@implementation DisclosureDetailController
@synthesize label;
- (void)viewDidUnload {
self.label = nil;
// OR [self.label release];
[super viewDidUnload];
}
- (void)dealloc {
[self.label release];
// OR self.label = nil;
}
las diferencias prácticas son las siguientes.
Establecer la propiedad a cero utilizando el acceso a la propiedad permitirá que el método sintetizado tome posesión de su nueva propiedad nula después de liberar la propiedad existente.
// we will take for granted that you synthesize this property
@property (nonatomic, retain) IBOutlet UILabel* label;
usaremos el acceso a la propiedad y lo estableceremos en cero.
//This will in actuality set the new value of nil to the label variable after
//releasing the existing label that it had a retain count on.
self.label = nil;
luego lo lanzaremos directamente
//This line on the other hand will merely release the label directly.
//As soon as the label is deallocated you will have a handle to an invalid object.
//(memory space that used to be your label)
[label release];
ahora mostraremos una versión simplificada del acceso a la propiedad. (no debe usarse literalmente)
//Simply put the following is an pseudo equivalent of the property setter.
[label release]
label = nil;
el punto principal aquí es que el descriptor de acceso a la propiedad maneja la liberación de la etiqueta que retuvo. y configurarlo para lo que sea que le des (en este caso es nulo)
por lo tanto, agregando el siguiente código
label = nil;
sin soltar el objeto retenido causaría una pérdida de memoria y tendría un conteo retenido en una etiqueta a la que ya no tiene un puntero.
Nota :
otra cosa a tener en cuenta. Cualquier puntero que sea nulo. podrá aceptar mensajes. Y a cambio responderán con nil. Por otro lado, un objeto que fue liberado, tan pronto como esa memoria es desasignada, su mensaje probablemente arrojará un error. el resultado es impredecible Esta es una buena razón para establecer sus propiedades a cero. No solo manejará la liberación del objeto que está sosteniendo. pero también le dará un objeto al que puede enviar mensajes de forma segura sin estallar.
Un buen punto @WaltSellers
Acceder a una variable, independientemente de si es el acceso de propiedad o la variable de instancia. - Después de que se haya lanzado por completo. Producirá acciones "indefinidas". Esto significa que el acceso puede actuar bien, o puede arruinar otras partes de la aplicación, o alternativamente puede explotar muy rápido y terminar la aplicación ofensiva. Básicamente establecer la variable a cero después de liberar le permitirá superar ese error.
Un consejo separado de mi parte
para superar el error de acceso de propiedad y la variable de instancia, simplemente @synthesize y le digo que establezca un nombre de variable.
@synthesize label = _label;
al hacer esto, me permite diferenciar la autoetiqueta de su variable de instancia. ya que no se puede acceder a la variable de etiqueta directamente sin el _