2009-09-06 12 views
19

Quiero crear un objeto en el Objetivo C pero no tengo una referencia al mismo.¿Está permitido [control de liberación] controlar la duración del objeto?

¿Se puede dejar que controla el objeto de su propia vida llamando [comunicado de auto]?

En caso de que se pregunte por qué necesito esto: quiero crear un objeto que se suscriba a algunas notificaciones, pero después de un tiempo el objeto ya no se necesita y debería desaparecer.

Entonces, ¿está permitido lo siguiente?

- (void) destroyMyself { 
     [[NSNotificationCenter defaultCenter] removeObserver:self]; 

    [self release]; 
} 
+0

Nunca he usado Cocoa, pero de lo que leo al azar en la versión web solo decremento un contador interno que el recolector de basura de tiempo de ejecución utiliza para saber cuándo recoger el objeto, por lo que esto podría permitirse, incluso si parece extraño. De nuevo, podría estar totalmente equivocado ya que es solo una suposición que hago de lo que leí hace algunas veces. – p4bl0

+0

En un entorno de recuento de referencias, no hay recolector de basura, por lo que el objeto se libera inmediatamente cuando el recuento de referencias llega a cero. (después de la llamada a [self release], el objeto se ha eliminado y desasignado) –

+1

Perfectamente válido. Es el comienzo de un "patrón de invalidación". Lo que probablemente también debería hacer es establecer una variable de instancia en SÍ en -init y NO en -destroyMyself. De esta forma, puede afirmar que la bandera es SÍ en otros métodos; si la respuesta es NO, usted sabe que su objeto se estaba usando después de que usted específicamente lo intentó dejar de ser válido. – bbum

Respuesta

9

Las reglas son simples. Solo debes liberar un objeto si lo tienes. es decir, el objeto se obtuvo con un método que comienza con "nuevo" o "alloc" o un método que contiene copia.

Cocoa Memory Management Rules

Un objeto no debe, por tanto, hacer [comunicado de auto] o [autorelease auto] a menos que haya hecho anteriormente [auto retener].

+1

amen! ............ –

+0

Hmm, excepto que la guía de programación Objective-C de Apple dice que init puede llamar a [self release] en caso de error: http://developer.apple.com/library/mac/documentation /cocoa/conceptual/ObjectiveC/Articles/ocAllocInit.html#//apple_ref/doc/uid/TP30001163-CH22-SW13 – user102008

+0

@ user102008: Punto justo, pero init es algo excepcional. – JeremyP

3

Es legal, pero tenga cuidado. Usted quiere ser seguro nada más va a enviarle un mensaje después de que se libere.

que he hecho este tipo de cosas para un esquema de fallas de vuelta antes de que teníamos CoreData.

3

Bien parte del protocolo es que si envía la liberación de uno mismo, entonces debería haber enviado conservo una vez, así que supongo que haces. Entonces no hay nada sospechoso. Quiero decir que el código de asignación debe ser capaz de controlar la vida útil de su instancia; en sí mismo solo puede prolongar su vida, nunca hacerlo más corto (ya que haciéndolo más corto, entonces dejaría repentinamente al propietario de la asignación con un puntero no válido).

+1

¿Estás diciendo que debería llamar [auto retención] en el método init? –

+0

básicamente sí. Quizás debería hacer que los usuarios de la clase usen un método de liberación automática como [ListenerClass listenerWithParam: param] ya que el usuario podría no retenerlo. Pero se requiere que * la liberación de la clase coincida con una llamada a alloc/retener por el usuario de la clase * broken * – u0b34a0f6ae

+1

No, no debe enviar -retain a self, porque ya tiene un conteo de retención distinto de cero después de + alloc. Siempre equilibre sus retiros y liberaciones. Si envía + alloc, + new, -copy o -retain, equilibre con -release o -autorelease. – NSResponder

4

citar el gran filósofo Alicia Silverstone, "I had an overwhelming sense of ickiness" cuando leí eso. Pero realmente no podría decirte por qué.

creo que me gustaría utilizar autorelease en lugar de un simple release ya que todavía está ejecutando el código en self cuando se llame, pero aparte de eso, no puedo pensar en ninguna razones técnicas por las que no funcionaría.

+0

Eso o: [self release]; self = nil; – Darren

18

Si ve esto en el código, probablemente sea incorrecto. Sin embargo, hay una respuesta legítima para ello en ciertas circunstancias que son discutiblemente defendibles. (Así que asegúrese de que está haciendo por las razones correctas.)

Un buen ejemplo de cuando esto tiene sentido, es cuando se crea un objeto que se va a descargar un URL. El objeto se almacena en la memoria mientras se descarga la url, luego envía un mensaje a su delegado diciendo que los datos están listos (o que la URL no se pudo descargar). Una vez que se ha enviado su mensaje, se destruye a sí mismo porque ya no es necesario. En esta situación, el código/función que creó el 'url downloader' puede ya no estar en la memoria, es decir, si se llamó en respuesta a una selección de usuario un elemento de menú o una acción en un controlador de vista que ya no está en la pantalla .

Esto es útil cuando el código que crea el objeto "descarga" no le importa si la descarga se haya completado o no.

+1

¿No puede su delegado hacer algo como '[emisión del emisor]', en lugar de que el remitente haga '[self release]'? – SK9

+1

+1 para la carga de URL ejemplo –

+1

Solía ​​hacer esto. Luego vino ARC. Esta forma de trabajar no funciona muy bien con ARC. –

2

Y voy a utilizar [auto autorelease] en lugar de [comunicado de auto]. Debido a que por lo general se le llama en

- (void)aMethod 
{ 
    [self.delegate aDelegateMethod:self]; 
    [self release]; 

//If you add code related to self here, after [self release], you are making a huge mistake. 
} 

Si utilizo [autorelease auto], todavía puedo hacer algo después de autorelease.

Cuestiones relacionadas