Utilisation de __autoreleasing dans l'exemple d'extrait de code

Le code suivant est tiré de "Le livre de recettes du développeur iOS 5" utilisé pour illustrer comment écrire une string dans un file. Il utilise __autoreleasing sans aucune explication. Pourquoi est-ce nécessaire?

NSError __autoreleasing error; ... if (![mySsortingng writeToFile:path atomically:YES error:&error) { NSLog(.... error.localizedFailureReason ...); return; } 

Pourquoi ne pas simplement déclarer l'erreur sur la stack sans l'utilisation de __autoreleasing?

—— MODIFIER —–

Question supplémentaire: pourquoi l'auteur déclare-t-il NSError et non NSError *?

C'est un indice pour le système de comptage automatique des references (ARC).

L'object d' error sera atsortingbué quelque part dans le code de NSSsortingng, donc le déclarer comme __autoreleasing dans votre code permet à ARC de connaître les caractéristiques de stockage. Autrement dit, lorsque l' error est définie, ce sera un object autoreleased.

Il vous manque ce qui se passe réellement dans ce code quand une variable est passée par reference et assignée dans un programme ARC. Prenons par exemple une erreur de fonction (BOOL): (NSError * __autoreleasing *)

Dans la programmation non-ARC, la fonction de sauvegarde ressemble à ceci:

 - (BOOL)save:(NSError * __autoreleasing *)myError { *myError = [[[NSError error] retain] autorelease] } 

Dans la programmation ARC, la fonction de sauvegarde ressemble à ceci:

 - (BOOL)save:(NSError * __autoreleasing *)myError { *myError = [[NSError alloc] init]; } 

Malgré ce que le code ARC ressemble, les deux fonctions de sauvegarde créent un object d'erreur qui a été conservé et libéré automatiquement.

C'est parce que dans la version ARC, le type de pointeur que myError détermine détermine ce qui se passe avec la memory management de l'object error. En effet, tant que le pointeur est de type __autoreleasing, la ligne d'affectation * myError est remplacée par

 *myError = [[[NSError error] retain] autorelease] 

lors de l'exécution.

Donc, si nous étions en quelque sorte en mesure de passer dans un pointeur du mauvais type, par exemple __strong à la fonction de sauvegarde, cela entraînerait la fonction de sauvegarde de faire la mauvaise chose.

Puisque le compilateur empêchera cela en créant une variable temporaire, le code fonctionnera dans les deux sens, mais transmettre un pointeur de type autre que __autoreleasing n'a pas de sens dans une perspective de programmation ARC.

A partir des notes de publication ARC sur https://developer.apple.com/library/ios/#releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html :

__autoreleasing est utilisé pour désigner les arguments transmis par reference (id *) et qui sont auto-libérés au return.

Il y a une déclaration implicite de __strong faite quand vous déclarez la variable, mais comme il est passé par reference, le compilateur a besoin de l'indice pour faire la bonne chose. Qu'il s'agisse ou non d'une variable de stack n'affecte pas le suivi de conservation / libération.

le code :

 __autoreleasing NSSsortingng *str = xx; 

sera compilé par ARC comme:

 NSSsortingng *str = xx.autorelease 

Eh bien, c'est une convention ARC pour utiliser le qualificateur __autoreleasing pour l'object passé par reference. L'explication est ici à partir du site clang:

4.3.2. Durée de stockage des objects __autoreleasing

Un programme est mal formé s'il déclare un object __autoreleasing d'une durée de stockage non automatique.

Justification: les pools d'autorelease sont liés au fil et à la scope actuels par leur nature. Bien qu'il soit possible d'avoir des objects temporaires dont les variables d'instance sont remplies d'objects auto-libérés, il n'y a aucun moyen qu'ARC puisse fournir une sorte de garantie de security.

Il s'agit d'un comportement indéfini si un pointeur non nul est affecté à un object __autoreleasing alors qu'un pool d'autorelease est dans la scope, puis que cet object est lu après l'abandon de la scope du pool autorelease.