Estou tentando resolver o quebra-cabeça.
__strong
é o padrão para todos os ponteiros de objetos retíveis do Objective-C como NSObject, NSString, etc. É uma referência forte. O ARC o equilibra com um -release
no final do escopo.
__unsafe_unretained
é igual à velha maneira. É usado para um ponteiro fraco sem reter o objeto retentível.
__weak
é semelhante, __unsafe_unretained
exceto que é uma referência fraca de zeragem automática, o que significa que o ponteiro será definido como nulo assim que o objeto referenciado for desalocado. Isso elimina o perigo de ponteiros pendentes e erros EXC_BAD_ACCESS.
Mas para que serve exatamente __autoreleasing
? Estou tendo dificuldade em encontrar exemplos práticos de quando preciso usar este qualificador. Acredito que seja apenas para funções e métodos que esperam um ponteiro-ponteiro, como:
- (BOOL)save:(NSError**);
ou
NSError *error = nil;
[database save:&error];
que sob ARC deve ser declarado desta forma:
- (BOOL)save:(NSError* __autoreleasing *);
Mas isso é muito vago e gostaria de entender o porquê . Os trechos de código que encontro colocam o __autoreleasing entre as duas estrelas, o que me parece estranho. O tipo é NSError**
(um ponteiro para NSError), então por que colocá-lo __autoreleasing
entre as estrelas e não simplesmente na frente delas NSError**
?
Além disso, pode haver outras situações nas quais devo confiar __autoreleasing
.
fonte
Respostas:
Você está certo. Conforme explica a documentação oficial:
Tudo isso é muito bem explicado no guia de transição ARC .
Em seu exemplo NSError, a declaração significa
__strong
, implicitamente:Será transformado em:
Quando você chama seu
save
método:O compilador terá então que criar uma variável temporária, definida em
__autoreleasing
. Assim:Será transformado em:
Você pode evitar isso declarando o objeto de erro como
__autoreleasing
, diretamente.fonte
__autoreleasing
só é usado para argumentos passados por referência. Este é um caso especial, pois você tem um ponteiro para o ponteiro de um objeto. Esse não é o caso de coisas como construtores de conveniência, já que eles apenas retornam um ponteiro para um objeto e o ARC o trata automaticamente.Seguindo a resposta do Macmade e a pergunta de acompanhamento do membro orgulhoso nos comentários (também teria postado isso como um comentário, mas excede a contagem máxima de caracteres):
É aqui que o qualificador variável de __autoreleasing é colocado entre as duas estrelas.
Para começar, a sintaxe correta para declarar um ponteiro de objeto com um qualificador é:
O compilador vai perdoar isso:
mas não está correto. Consulte o guia de transição do Apple ARC (leia a seção que começa com "Você deve decorar as variáveis corretamente ...").
Para responder à questão em questão: Um ponteiro duplo não pode ter um qualificador de gerenciamento de memória ARC porque um ponteiro que aponta para um endereço de memória é um ponteiro para um tipo primitivo, não um ponteiro para um objeto. No entanto, quando você declara um ponteiro duplo, o ARC deseja saber quais são as regras de gerenciamento de memória para o segundo ponteiro. É por isso que as variáveis de ponteiro duplo são especificadas como:
Portanto, no caso de um argumento de método que é um ponteiro NSError duplo, o tipo de dados é declarado como:
que em inglês diz "ponteiro para um ponteiro de objeto __autoreleasing NSError".
fonte
A especificação ARC definitiva diz que
Por exemplo, o código
na verdade é convertido para
... é por isso que funciona quando você tem um parâmetro
NSError* __autoreleasing * errorPointer
, o método chamado atribuirá o erro a*errorPointer
e a semântica acima será ativada.Você poderia usar
__autoreleasing
em um contexto diferente para forçar um objeto ARC no pool de autorelease, mas isso não é muito útil, uma vez que o ARC só parece usar o pool de autorelease no retorno do método e já controla isso automaticamente.fonte