ARC - ¿El significado de __unsafe_unretained?

80

Solo quiero asegurarme de que lo hice bien:

  1. ¿Necesito __unsafe_unretainobjetos que no me pertenecen?
  2. Si un objeto es __unsafe_unretained¿Necesito usarlo assignen el @property? ¿Significa eso que el objeto no se retiene y solo se refiere al objeto que le asigno?
  3. ¿Cuándo querría usarlo excepto para los delegados?
  4. ¿Es eso una cosa ARC o estaba en uso antes?
Shannoga
fuente

Respuestas:

192

El compilador LLVM 3.0 presenta cuatro nuevos calificadores de propiedad: __strong, __autoreleasing, __unsafe_unretained, y __weak. Los tres primeros están disponibles incluso fuera de ARC, según la especificación .

Como indica Joshua, de forma predeterminada, todos los punteros están implícitos __strongen ARC. Esto significa que cuando se asigna un objeto a ese puntero, se retiene durante el tiempo que ese puntero se refiere a él. Esto está bien para la mayoría de las cosas, pero abre la posibilidad de retener ciclos, como describo en mi respuesta aquí . Por ejemplo, si tiene un objeto que contiene otro objeto como variable de instancia, pero ese segundo objeto tiene un vínculo fuerte con el primero como su delegado, los dos objetos nunca se liberarán.

Es por esta razón que existen los calificadores __unsafe_unretainedy __weak. Su uso más común es para los delegados, donde definiría una propiedad para ese delegado con el atributo weako unsafe_unretained( assignes efectivamente unsafe_unretained), y luego lo emparejaría marcando la variable de instancia respectiva con __weako __unsafe_unretained. Esto significa que la variable de instancia delegada seguirá apuntando al primer objeto, pero no hará que ese objeto se retenga, rompiendo así el ciclo de retención y permitiendo que ambos objetos se liberen.

Más allá de los delegados, esto es útil para romper cualquier otro ciclo de retención que pueda formarse en su código. De manera útil, el instrumento Leaks ahora incluye una vista de Ciclos, que muestra los ciclos de retención que descubre en su aplicación de manera gráfica.

Ambos __unsafe_unretainedy __weakprevienen la retención de objetos, pero de formas ligeramente diferentes. Porque __weak, el puntero a un objeto se convertirá nilen la desasignación del objeto al que apunta, lo que es un comportamiento muy seguro. Como su nombre lo indica, __unsafe_unretainedseguirá apuntando a la memoria donde estaba un objeto, incluso después de haber sido desasignado. Esto puede provocar bloqueos debido al acceso a ese objeto desasignado.

¿Por qué lo usarías __unsafe_unretainedentonces? Desafortunadamente, __weaksolo es compatible con iOS 5.0 y Lion como destinos de implementación. Si desea volver a apuntar a iOS 4.0 y Snow Leopard, debe usar el __unsafe_unretainedcalificador o usar algo como MAZeroingWeakRef de Mike Ash .

Brad Larson
fuente
2
Y, por supuesto, __unsafe_unretainedpuede ser útil para definir matrices C de NSStringconstantes y similares, por ejemploNSString __unsafe_unretained *myStrings = { @"Foo", @"Bar", @"Baz", nil };
jlehr
2
@shannoga: no, debe especificar manualmente __weakcomo calificador para que use ese tipo de punteros. Aún puede usarlo __unsafe_unretainedcon un objetivo puramente 5.0 y no se comportará como __weak. Si desea algo que cambie entre los dos modos dependiendo de si su objetivo lo admite, puede usar una definición específica del compilador como sugiero aquí: stackoverflow.com/a/8594878/19679
Brad Larson
4
@jlehr: NSString *myStrings = { @"Foo", @"Bar" };no es una sintaxis válida de Objective-C; @"Foo"tiene tipo NSString*por sí mismo. Quizás quisiste decir NSString *myStrings[] = { @"Foo", @"Bar" };, pero en ese caso realmente no entiendo cómo __unsafe_unretainedsería especialmente útil.
Quuxplusone
2
@Quuxplusone Correcto en ambos aspectos: estaba mezclando matrices C con estructuras. Lo que debería haber dicho es que __unsafe_unretainedpueden ser miembros útiles de estructuras C que apuntan a constantes NSString, por ejemplostruct foo { __unsafe_unretained NSString * const s; int x; };
jlehr
1
También tiene implicaciones para Class. Ver: stackoverflow.com/a/14245894/392847
Quintin Willison
4
  1. No, también puede utilizarlo weakpara objetos que no le pertenecen.
  2. No, también se puede utilizar unsafe_unretaineden la propiedad.
  3. Tengo entendido que los unsafe_unretainedelementos son iguales weak, sin la seguridad adicional de eliminarlos cuando se libera el elemento al que apuntan (y los gastos generales que lo acompañan).
  4. Esto es completamente una cosa de ARC.
Sergey Kalinichenko
fuente
En realidad, por extraño que parezca, las unsafe_unretainediVars, cuando se configuran en tiempo de ejecución, se comportan como strongunas, lo que me lleva a creer que unsafe_unretainedes simplemente una pista del compilador, mientras que las débiles no lo son. Más información aquí: stackoverflow.com/questions/11621028/…
Richard J. Ross III
4

__unsafe_unretainedes idéntico al almacenamiento predeterminado de un objeto antes de ARC. Con ARC, el valor predeterminado ahora __strongsignifica que tiene una referencia a él hasta que su referencia salga del alcance.

Joshua Weinberg
fuente
1

Otra observación sobre __unsafe_unretained: ¡Tengo bloqueos en mi aplicación en el dispositivo y NO en el simulador con iVars declaradas como __unsafe_unretained! Sí, fue un error en el código de la migración de ARC, pero fue la primera vez que noté tal diferencia entre el dispositivo y el simulador.

Gerd
fuente