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 __strong
en 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_unretained
y __weak
. Su uso más común es para los delegados, donde definiría una propiedad para ese delegado con el atributo weak
o unsafe_unretained
( assign
es efectivamente unsafe_unretained
), y luego lo emparejaría marcando la variable de instancia respectiva con __weak
o __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_unretained
y __weak
previenen la retención de objetos, pero de formas ligeramente diferentes. Porque __weak
, el puntero a un objeto se convertirá nil
en la desasignación del objeto al que apunta, lo que es un comportamiento muy seguro. Como su nombre lo indica, __unsafe_unretained
seguirá 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_unretained
entonces? Desafortunadamente, __weak
solo 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_unretained
calificador o usar algo como MAZeroingWeakRef de Mike Ash .
__unsafe_unretained
puede ser útil para definir matrices C deNSString
constantes y similares, por ejemploNSString __unsafe_unretained *myStrings = { @"Foo", @"Bar", @"Baz", nil };
__weak
como calificador para que use ese tipo de punteros. Aún puede usarlo__unsafe_unretained
con 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/19679NSString *myStrings = { @"Foo", @"Bar" };
no es una sintaxis válida de Objective-C;@"Foo"
tiene tipoNSString*
por sí mismo. Quizás quisiste decirNSString *myStrings[] = { @"Foo", @"Bar" };
, pero en ese caso realmente no entiendo cómo__unsafe_unretained
sería especialmente útil.__unsafe_unretained
pueden ser miembros útiles de estructuras C que apuntan a constantes NSString, por ejemplostruct foo { __unsafe_unretained NSString * const s; int x; };
Class
. Ver: stackoverflow.com/a/14245894/392847weak
para objetos que no le pertenecen.unsafe_unretained
en la propiedad.unsafe_unretained
elementos son igualesweak
, sin la seguridad adicional de eliminarlos cuando se libera el elemento al que apuntan (y los gastos generales que lo acompañan).fuente
unsafe_unretained
iVars, cuando se configuran en tiempo de ejecución, se comportan comostrong
unas, lo que me lleva a creer queunsafe_unretained
es simplemente una pista del compilador, mientras que las débiles no lo son. Más información aquí: stackoverflow.com/questions/11621028/…__unsafe_unretained
es idéntico al almacenamiento predeterminado de un objeto antes de ARC. Con ARC, el valor predeterminado ahora__strong
significa que tiene una referencia a él hasta que su referencia salga del alcance.fuente
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.
fuente