Dans quelles situations avons-nous besoin d'écrire le qualificatif de propriété __autoreleasing sous ARC?

J'essaie de compléter le puzzle.

__strong est la valeur par défaut pour tous les pointeurs d'object __strong par Objective-C comme NSObject, NSSsortingng, etc. C'est une reference forte. ARC l'équilibre avec une- -release à la fin de la scope.

__unsafe_unretained est égal à l'ancienne. Il est utilisé pour un pointeur faible sans conserver l'object conservable.

__weak est comme __unsafe_unretained sauf que c'est une reference faible auto-mise à zéro, ce qui signifie que le pointeur sera mis à zéro dès que l'object référencé est libéré. Cela élimine le danger de balancer des pointeurs et des erreurs EXC_BAD_ACCESS.

Mais qu'est-ce qui est bon pour __autoreleasing ? J'ai de la difficulté à find des exemples pratiques quand j'ai besoin d'utiliser ce qualificatif. Je crois que c'est seulement pour les fonctions et les methods qui attendent un pointeur de point tel que:

 - (BOOL)save:(NSError**); 

ou

 NSError *error = nil; [database save:&error]; 

qui sous ARC doit être déclaré de cette façon:

 - (BOOL)save:(NSError* __autoreleasing *); 

Mais c'est trop vague et j'aimerais bien comprendre pourquoi . Les extraits de code que je trouve placent le __autoreleasing entre les deux écanvass, ce qui me semble bizarre. Le type est NSError** (un pointeur pointeur sur NSError), alors pourquoi placer __autoreleasing entre les écanvass et pas simplement devant NSError** ?

En outre, il peut y avoir d'autres situations dans lesquelles je dois countr sur __autoreleasing .

Tu as raison. Comme la documentation officielle explique:

__autoreleasing pour indiquer les arguments passés par reference (id *) et qui sont auto-libérés au return.

Tout cela est très bien expliqué dans le guide de transition ARC .

Dans votre exemple NSError, la déclaration signifie __strong , implicitement:

 NSError * e = nil; 

Sera transformé en:

 NSError * __strong error = nil; 

Lorsque vous appelez votre méthode de save :

 - ( BOOL )save: ( NSError * __autoreleasing * ); 

Le compilateur devra alors créer une variable temporaire, définie sur __autoreleasing . Alors:

 NSError * error = nil; [ database save: &error ]; 

Sera transformé en:

 NSError * __strong error = nil; NSError * __autoreleasing tmpError = error; [ database save: &tmpError ]; error = tmpError; 

Vous pouvez éviter cela en déclarant directement l'object error en tant que __autoreleasing .

Suite à la réponse de Macmade et à la question de suivi de Fier membre dans les commentaires, (aurait également posté ceci comme un commentaire, mais il dépasse le nombre maximal de caractères):

Voici pourquoi le qualificateur variable de __autoreleasing est placé entre les deux écanvass.

Pour préface, la syntaxe correcte pour déclarer un pointeur d'object avec un qualificateur est:

 NSError * __qualifier someError; 

Le compilateur pardonnera ceci:

 __qualifier NSError *someError; 

mais ce n'est pas correct. Voir le guide de transition Apple ARC (lisez la section qui commence par "Vous devriez décorer correctement les variables …").

Pour adresser à la question à scope de main: Un pointeur double ne peut pas avoir un qualificateur de gestion de memory ARC parce qu'un pointeur qui pointe vers une adresse de memory est un pointeur vers un type primitif, pas un pointeur vers un object. Cependant, lorsque vous déclarez un double pointeur, ARC veut savoir quelles sont les règles de memory management pour le second pointeur. C'est pourquoi les variables à double pointeur sont spécifiées comme:

 SomeClass * __qualifier *someVariable; 

Ainsi, dans le cas d'un argument de méthode qui est un double pointeur NSError, le type de données est déclaré comme suit:

 - (BOOL)save:(NSError* __autoreleasing *)errorPointer; 

qui en anglais dit "pointer vers un pointeur d'object NSError __autoreleasing".

La spécification ARC définitive dit que

Pour les objects __autoreleasing, le nouveau pointeur est conservé, auto-libéré et stocké dans la lvalue en utilisant la sémantique primitive.

Ainsi, par exemple, le code

 NSError* __autoreleasing error = someError; 

est en fait converti en

 NSError* error = [[someError retain] autorelease]; 

… c'est pourquoi cela fonctionne quand vous avez un paramètre NSError* __autoreleasing * errorPointer , la méthode appelée va alors assigner l'erreur à *errorPointer et la sémantique ci-dessus sera *errorPointer .

Vous pouvez utiliser __autoreleasing dans un context différent pour forcer un object ARC dans le pool autorelease, mais ce n'est pas très utile car ARC semble seulement utiliser le pool autorelease au return de la méthode et le gère déjà automatiquement.