2009-07-31 19 views
33

Así que pensé que tenía todas estas preguntas completamente resueltas. Entonces, de repente, recibo un error (un bloqueo) que no puedo entender. Luego, después de investigar para remediar el accidente, noto que todo lo que creía saber sobre estas áreas críticas es algo erróneo.Release, Dealloc y Self Reference

A continuación se presentan 8 preguntas Voy a disparar por ahí con la esperanza de que alguien responda - las respuestas a estas me ayudarán enormemente a recuperar mi comprensión. Gracias de antemano!

Q1) ¿Está bien invocar Release en un objeto si esa referencia es nula? Esto debería ser inofensivo, ¿verdad?

Q2) ¿Está bien invocar Release en un objeto si esa referencia se ha liberado y como un recuento de referencia de 0?

Q3) ¿Es necesario establecer una referencia a nula DESPUÉS de soltarlo? ¿Qué pasa si no lo configuras a cero?

Q4) ¿Existe realmente una diferencia entre nulo y NULL, o es solo una cuestión semántica ayudar al lector/desarrollador a conocer el tipo de objeto simplemente mirándolo?

Q5) ¿El uso de propiedades REQUIERE el uso del puntero 'Self'?

Q6) El uso de variables de instancia requiere que NO se use el puntero 'Self'?

Q7) ¿Cuándo alguna vez querría usar una variable de instancia en lugar de su propiedad? Me imagino que los miembros de datos de tipo de valor están bien, ya que no están liberando y manteniendo involucrados.

Q8) ¿Es necesario llamar a dealloc de un objeto desde la función dealloc? En muchos ejemplos he visto que se llama a Release, pero no a Dealloc: ¿son incorrectos estos tutoriales?

+0

Nice q.Acabo de encontrar algunas preguntas nuevas que ni siquiera sabía que quería responder. – typeoneerror

Respuesta

11

Probablemente deberías haber dividido esta pregunta en varias preguntas diferentes, pero voy a morder.

  1. Sí, cualquier mensaje enviado a nil es un no-op.
  2. No. Se ha destruido, o se destruirá inminentemente, un objeto con 0 y cualquier mensaje enviado a él provocará un bloqueo, o en el mejor de los casos, una excepción.
  3. Depende de la situación. Si está publicando cosas en -dealloc, entonces probablemente no. Si se trata de un objeto que tiene un alcance determinado para un método en particular, entonces probablemente no. Si se trata de un ivar reutilizado, diría que sí. En los primeros dos casos, no pasará nada si no configura los punteros a cero, ya que normalmente ya no podrá acceder a esos punteros. Sin embargo, en el último caso, aún puede acceder al puntero, que apunta a la memoria desasignada. Si le envía un mensaje o intenta desreferenciarlo, su aplicación se bloqueará.
  4. Ambos son iguales a 0. Por convenio nil se utiliza para punteros de objetos, y NULL se usa para cualquier otro puntero, pero mezclarlos no causará ningún problema.
  5. Si desea invocar la propiedad getter/setter, entonces sí. Si desea acceder al ivar, encapsula directamente (poco común), no.
  6. No, puede acceder a las variables de instancia utilizando la sintaxis self->ivar. De hecho, cuando escribe solo ivar, el compilador agrega implícitamente la desreferenciación self->.
  7. No estoy seguro de lo que quiere decir aquí.
  8. La única vez que debe llamar al -dealloc es cuando llama al [super dealloc]; en sus propios métodos -dealloc. Para cualquier otro objeto, siempre debe llamar al -release.
+0

En (2) NSZombieEnabled debe mencionarse. Hace que la depuración de problemas de asignación sea fácil. – diciu

+0

"fácil" es una palabra fuerte! Yo diría "más fácil". –

19

A1) [nil release] está bien (no hacer nada)

A2) No. No toque los objetos después de que hayan sido desasignado. Deben establecerse en cero después de que se liberen.

A3) No es necesario establecer un puntero liberado en cero, pero se obtienen punteros colgantes (es decir, no se puede decir si un objeto es válido o no). Establecer una propiedad en nil a menudo se usa para liberar el ivar subyacente, por lo que no hacerlo puede causar una pérdida de memoria

A4) nulo y NULL son ambos cero, por lo que técnicamente son los mismos.

A5) Sí, debe utilizar self.someProperty de propiedades, del mismo modo que utiliza [self someProperty] si era sólo un método

A6) sí es esencialmente una estructura, para que pueda acceder Ivars, así: self->someIvar. No es necesario, sin embargo.

A7) Cuando no desea ejecutar los métodos setter/getter por cualquier razón. Lo uso ocasionalmente cuando el colocador no permite valores nulos, y necesito liberar la variable

A8) dealloc se invoca automáticamente cuando la versión se llama la cantidad correcta de veces. Nunca debe llamar a dealloc directamente (a excepción de [super dealloc])

+1

Estoy confundido con # 5. Tengo una @propiedad no tática, retenida llamada "social" en un controlador de vista y estas declaraciones registran lo mismo: NSLog (@ "% @", social); y NSLog (@ "% @", self.social); ¿Puedes explicarlo, Tom? – typeoneerror

+1

Eso es porque ambas instrucciones 'NSLog' están imprimiendo el mismo objeto. La diferencia es que 'self.social' llama a un método que devuelve el objeto, y' social' es solo el objeto en sí. –

8

Otros han respondido adecuadamente al 1-6.

(7) Apple recomienda utilizar la variable de instancia directamente en init y dealloc. Principalmente esto se debe a que el objeto (especialmente si está subclasificado) está configurado solo parcialmente durante estos dos métodos, por lo que llamar a setters/getters puede dar como resultado un comportamiento incorrecto si tienen algo más que acciones triviales. En general, puede acceder de manera segura al ivar directamente (en lugar de a través del getter) en su objeto, y será marginalmente más eficiente para hacerlo (solo relevante en el iPhone). En general, debe usar el colocador en todos los casos, especialmente si su objeto puede estar subclasificado o si otros pueden estar observando la propiedad.

(8) Nunca, nunca, llame a dealloc (excepto [super dealloc] desde dentro del método dealloc). Si tiene una propiedad sobre otro objeto, entonces debe renunciar a esa propiedad (llamando al lanzamiento o a la liberación automática). El sistema llamará a dealloc sobre el objeto si corresponde. Pero nunca llamas a dealloc tú mismo. Lea el memory management rules (son solo 9 párrafos y es vital para entender).

+0

gracias. encontré el enlace a las reglas de MM en algún lugar que alguien señaló. Lo leeré definitivamente. –

+0

Por cierto, todas estas preguntas surgieron cuando mi idea de liberar y nada se rompió después de un choque inesperado (la aplicación se bloquea después de establecer una referencia a cero). ¿Por qué diablos sería asignar un puntero a cero estrellar la aplicación? Desde entonces he estado usando 'self' cada lugar donde asigno un puntero a otra referencia. –

+0

El único motivo por el que establecer una referencia a nil se bloquearía sería si la referencia formaba parte de un objeto no válido o desasignado. Habilite NSZombies y quizás eso ayude. –

0

Ok. He confirmado que no configurar B a nil hizo el truco. Así que, ahora, no compruebo nada cuando creo el controlador B (cuando quiero navegar hacia él).

En cambio, libero a B, entonces creo el controlador y asignarla a B. Luego, en el método de viewDidAppear A, libero B.

Creo que este hilo se ha cerrado. ¡Gracias!

0

A4) Se diferencian en sus tipos. Todos son cero, pero NULL es un vacío *, nil es una identificación y Nil es un puntero de clase.