objective-c - sistema - swift versions
¿Por qué a los delegados de Objective-C generalmente se les asigna la propiedad en lugar de retener? (4)
Estoy navegando por el maravilloso blog mantenido por Scott Stevenson, y estoy tratando de comprender un concepto fundamental de Objective-C de asignar a los delegados la propiedad ''asignar'' frente a ''retener''. Tenga en cuenta que ambos son iguales en un entorno recolectado de basura. Me preocupa sobre todo un entorno no basado en GC (p. Ej .: iPhone).
Directamente del blog de Scott:
"La palabra clave assign generará un setter que asigna el valor a la variable de instancia directamente, en lugar de copiarlo o retenerlo. Esto es mejor para tipos primitivos como NSInteger y CGFloat, u objetos que no son de su propiedad, como los delegados".
¿Qué significa que usted no posee directamente el objeto delegado? Normalmente retengo a mis delegados, porque si no quiero que se vayan al abismo, retener se encargará de eso por mí. Normalmente, elimino UITableViewController de su respectivo dataSource y también lo delego. También retengo ese objeto en particular. Quiero asegurarme de que nunca desaparezca, por lo que mi UITableView siempre tiene su delegado.
¿Alguien más puede explicar dónde / por qué estoy equivocado, entonces puedo entender este paradigma común en la programación de Objective-C 2.0 de usar la propiedad assign en los delegados en lugar de retener?
¡Gracias!
La razón por la que evita retener delegados es que necesita evitar un ciclo de retención:
A crea B A se establece como delegado de B ... A es lanzado por su propietario
Si B hubiera retenido A, A no se liberaría, ya que B posee A, por lo tanto, nunca se llamaría al dealloc de A, lo que provocaría que tanto A como B fugasen.
No debes preocuparte porque A se vaya porque posee B y así se deshace de él en dealloc.
Porque el objeto que envía los mensajes de delegado no posee el delegado.
Muchas veces, es al revés, como cuando un controlador se establece como delegado de una vista o ventana: el controlador posee la vista / ventana, por lo que si la vista / ventana posee su delegado, ambos objetos se poseerán entre sí. Esto, por supuesto, es un ciclo de retención, similar a una fuga con la misma consecuencia (los objetos que deberían estar muertos permanecen vivos).
Otras veces, los objetos son pares: ninguno posee el otro, probablemente porque ambos pertenecen al mismo tercer objeto.
De cualquier manera, el objeto con el delegado no debe retener su delegado.
(Por cierto, hay al menos una excepción. No recuerdo qué era, y no creo que haya una buena razón para ello).
Addendum (agregado 2012-05-19): En ARC, debe usar weak
lugar de assign
. Las referencias débiles se configuran como nil
automáticamente cuando el objeto muere, lo que elimina la posibilidad de que el objeto delegado termine enviando mensajes al delegado muerto.
Si te mantienes alejado de ARC por alguna razón, al menos cambia las propiedades de assign
que apuntan a los objetos a unsafe_unretained
, lo que hace explícito que esta es una referencia no retenida pero no cero a un objeto.
assign
sigue siendo apropiado para valores no objeto tanto en ARC como en MRC.
Tenga en cuenta que cuando tiene un delegado asignado, es muy importante establecer siempre ese valor delegado en cero siempre que el objeto vaya a ser desasignado, por lo que un objeto siempre debe tener cuidado de no delegar referencias en dealloc si no lo ha hecho hecho así en otro lugar.
Una de las razones detrás de esto es evitar los ciclos de retención. Solo para evitar el escenario donde A y B ambos objetos se referencian entre sí y ninguno de ellos se libera de la memoria.
Acutally assign es mejor para tipos primitivos como NSInteger y CGFloat, u objetos que no son de su propiedad directamente, como los delegados.