Estoy intentando completar el rompecabezas.
__strong
es el valor predeterminado para todos los punteros de objetos retenibles de Objective-C como NSObject, NSString, etc. Es una referencia sólida. ARC lo equilibra con un -release
al final del alcance.
__unsafe_unretained
es igual a la forma antigua. Se usa para un puntero débil sin retener el objeto retenible.
__weak
es como __unsafe_unretained
excepto que es una referencia débil de puesta a cero automática, lo que significa que el puntero se establecerá en cero tan pronto como se desasigne el objeto referenciado. Esto elimina el peligro de punteros colgantes y errores EXC_BAD_ACCESS.
Pero, ¿para qué sirve exactamente __autoreleasing
? Me cuesta encontrar ejemplos prácticos sobre cuándo necesito usar este calificador. Creo que es solo para funciones y métodos que esperan un puntero-puntero como:
- (BOOL)save:(NSError**);
o
NSError *error = nil;
[database save:&error];
que bajo ARC debe declararse de esta manera:
- (BOOL)save:(NSError* __autoreleasing *);
Pero esto es demasiado vago y me gustaría entender completamente por qué . Los fragmentos de código que encuentro colocan el __autoreleasing entre las dos estrellas, lo que me parece extraño. El tipo es NSError**
(un puntero-puntero a NSError), entonces, ¿por qué colocarlo __autoreleasing
entre las estrellas y no simplemente frente a ellas NSError**
?
Además, puede haber otras situaciones en las que deba confiar __autoreleasing
.
fuente
Respuestas:
Tienes razón. Como explica la documentación oficial:
Todo esto está muy bien explicado en la guía de transición ARC .
En su ejemplo de NSError, la declaración significa
__strong
, implícitamente:Se transformará en:
Cuando llamas a tu
save
método:El compilador tendrá que crear una variable temporal, establecida en
__autoreleasing
. Entonces:Se transformará en:
Puede evitar esto declarando el objeto de error como
__autoreleasing
, directamente.fuente
__autoreleasing
solo se usa para argumentos pasados por referencia. Este es un caso especial, ya que tiene un puntero al puntero de un objeto. Ese no es el caso con cosas como los constructores de conveniencia, ya que solo devuelven un puntero a un objeto y ARC lo maneja automáticamente.Continuando con la respuesta de Macmade y la pregunta de seguimiento de Proud Member en los comentarios (también habría publicado esto como comentario, pero supera el número máximo de caracteres):
He aquí por qué el calificador variable de __autoreleasing se coloca entre las dos estrellas.
Para comenzar, la sintaxis correcta para declarar un puntero de objeto con un calificador es:
El compilador perdonará esto:
pero no es correcto. Consulte la guía de transición de Apple ARC (lea la sección que comienza "Debería decorar las variables correctamente ...").
Para abordar la pregunta en cuestión: un puntero doble no puede tener un calificador de gestión de memoria ARC porque un puntero que apunta a una dirección de memoria es un puntero a un tipo primitivo, no un puntero a un objeto. Sin embargo, cuando declara un puntero doble, ARC quiere saber cuáles son las reglas de administración de memoria para el segundo puntero. Es por eso que las variables de doble puntero se especifican como:
Entonces, en el caso de un argumento de método que es un puntero doble NSError, el tipo de datos se declara como:
que en inglés dice "puntero a un puntero de objeto NSError de liberación automática".
fuente
La especificación definitiva de ARC dice que
Entonces, por ejemplo, el código
en realidad se convierte en
... razón por la cual funciona cuando tiene un parámetro
NSError* __autoreleasing * errorPointer
, el método llamado asignará el error*errorPointer
y la semántica anterior se activará.Puede usarlo
__autoreleasing
en un contexto diferente para forzar un objeto ARC en el grupo de liberación automática, pero eso no es muy útil ya que ARC solo parece usar el grupo de liberación automática en el retorno del método y ya lo maneja automáticamente.fuente