with tutorial framework espaƱol djangoproject desde con cero applications objective-c cocoa cocoa-touch memory-management

objective c - tutorial - Asignar e iniciar objetos en el Objetivo C



tutorial django (6)

Cada objeto tiene un recuento de referencia. Cuando va a 0, el objeto se desasigna.

Suponiendo que la propiedad se declaró como @property (retain) :

Tu primer ejemplo, línea por línea:

  1. El objeto es creado por alloc , tiene un recuento de referencia de 1.
  2. El objeto se entrega al método setAController: , que le envía un mensaje de retain (porque el método no sabe de dónde viene el objeto), incrementando su recuento de referencia a 2.
  3. El código de llamada ya no necesita el objeto en sí, por lo que llama a release , disminuyendo el recuento de referencia a 1.

Su segundo ejemplo básicamente hace los pasos 1 y 2 pero no 3, por lo que al final el recuento de referencia del objeto es 2.

La regla es que si creas un objeto, eres responsable de liberarlo cuando hayas terminado con él. En su ejemplo, el código se hace con tempAController después de establecer la propiedad. Es responsabilidad del método setter llamar a retain si necesita que ese objeto permanezca.

Es importante recordar que self.property = foo; en Objective-C realmente es solo una abreviatura de [self setProperty:foo]; y que el método setProperty: va a retener o copiar objetos según sea necesario.

Si la propiedad se declaró @property (copy) , entonces el objeto se habría copiado en lugar de retenerse. En el primer ejemplo, el objeto original sería lanzado de inmediato; en el segundo ejemplo, el recuento de referencia del objeto original sería 1, aunque debería ser 0. Por lo tanto, aún desea escribir el código de la misma manera.

Si la propiedad fue declarada @property (assign) , entonces self no reclama la propiedad del objeto y alguien más debe retenerlo. En este caso, el primer ejemplo sería incorrecto. Este tipo de propiedades son raras, generalmente solo se usan para delegados de objeto.

¿Cuál es la diferencia entre las 2 formas siguientes de asignar e iniciar un objeto?

AController *tempAController = [[AController alloc] init]; self.aController = tempAController; [tempAController release];

y

self.aController= [[AController alloc] init];

La mayoría de los ejemplos de apple usan el primer método. ¿Por qué asignar, iniciar y objetar y luego liberar inmediatamente?


Como otros han notado, los dos fragmentos de código que muestra no son equivalentes (por razones de administración de memoria). En cuanto a por qué el primero se elige sobre el segundo:

La formulación correcta de este último sería

self.aController= [[[AController alloc] init] autorelease];

Comparado con el primero, esto agrega una sobrecarga adicional mediante el uso del grupo de autorrelease y, en algunas circunstancias, prolongará innecesariamente la duración del objeto (hasta que se libere el grupo de autorrelease) lo que aumentará la huella de memoria de su aplicación.

La otra implementación "posible" (dependiendo de dónde sea el ejemplo) es simplemente:

aController = [[AController alloc] init];

Sin embargo, no se recomienda establecer directamente una variable de instancia en ningún otro lugar que no sea un método init o dealloc. En otros lugares, siempre debes usar métodos de acceso.

Esto nos lleva luego a la implementación que se muestra en el código de muestra:

AController *tempAController = [[AController alloc] init]; self.aController = tempAController; [tempAController release];

Esto sigue las mejores prácticas ya que:

  • Evita la liberación automática;
  • Hace que la semántica de gestión de la memoria sea inmediata;
  • Utiliza un método de acceso para establecer la variable de instancia.

Otra cosa a tener en cuenta es que su ejemplo también depende de la definición @property de aController.

Si se definió como @property (readwrite, retain) id aController; entonces su ejemplo funciona, mientras que si se define como @property (readwrite, assign) id aController; entonces la llamada extra a liberar causaría que su objeto fuera desasignado.


Si está utilizando Xcode, puede ayudarlo a detectar dicho código con el analizador estático. Solo toca Build >> Build and Analyze

Esto le mostrará un mensaje muy útil en tales fragmentos de código.


También podrías hacer

@property (nonatomic, retain)AController *aController; ... self.aController= [[AController alloc] init]; [aController release];

con una propiedad de retención, y funcionaría de la misma manera, pero es mejor usarlo de otra manera (para conservar propiedades) porque es menos confuso, ese código hace que parezca que usted asigna un Controlador y luego se borra de la memoria, cuando en realidad no lo hace porque setAController lo conserva.


Tenga en cuenta también que su deseo de reducir el código a una línea es el motivo por el que muchas personas utilizan Autorelease:

self.aController = [[[AController alloc] init] autorelease];

Aunque en teoría en la liberación automática de iPhone es de alguna manera más caro (nunca escuché una explicación clara de por qué) y por lo tanto es posible que desee liberar explícitamente justo después de asignar el objeto en otro lugar.