web-dev-qa-db-fra.com

Objectif c libération, autorelease et types de données

Je suis nouveau dans le code géré de la mémoire mais je reçois assez bien l'idée.

Lors de la prise de mon application via l'outil de fuites en Xcode, j'ai remarqué que je n'ai pas eu à nettoyer mes objets personnalisés, mais pas de réseaux créés de manière dynamique, par exemple, j'ai pensé que ces types de données sont de logement, ce qui a du sens puisque je n'ai que je n'ai que je n'ai que je n'ai que je n'ai plus que de libérer les tableaux J'ai utilisé comme propriétés qui ont eu un (conservation) sur eux.

Ensuite, j'ai remarqué quelque chose de particulier: j'avais une fuite sur un certain tableau initialisé comme ceci:

NSMutableArray *removals = [NSMutableArray new];

mais pas un similaire

NSMutableArray *removals = [NSMutableArray arrayWithCapacity:9];

Maintenant, la raison pour laquelle on a été créée avec "nouveau", c'est qu'il pourrait avoir 0 à 99 objets, alors que l'autre que je savais allait toujours être 9. Puisque les deux tableaux sont transmis à la même méthode plus tard en fonction de l'utilisateur Interaction, je recevais une fuite si je ne me suis pas libéré à la fin de la méthode, ni une exception si je l'ai fait!

J'ai changé le premier tableau à

NSMutableArray *removals = [NSMutableArray arrayWithCapacity:99];

et je ne reçois aucune fuite et je n'ai rien à libérer. Quelqu'un peut-il expliquer?

25
Michael

Comme indiqué dans la section Règles de gestion de la mémoire , chaque fois que vous avez un objet que vous avez créé avec +alloc, +new, -copy, ou -mutableCopy, vous possédez-le et êtes responsable de la libérer à un moment donné. (En réalité, +new juste sténographie pour [[MyClass alloc] init].) Comme vous l'avez noté, créez un tableau via [NSArray new] Sans libérer que c'est une fuite de mémoire. Cependant, si vous gérez correctement cet objet, il est généralement possible de le libérer à un moment donné. Par exemple:

  • Si la méthode utilise , le tableau est appelé de dans la méthode que Crée le tableau, vous devriez être capable de libérer la matrice après avoir été utilisée. Si la méthode interne doit conserver une référence plus permanente à la matrice autour, cette méthode est responsable de l'envoi -retain et éventuellement, -release à l'objet. Par exemple:

    - (void)myMethod {
        NSArray *removals = [NSArray new];
        // ...
        [someObject someOtherMethod:removals];
        [removals release];
    }
    
  • Si vous avez créé le tableau dans un -init Méthode Pour un objet, alors le -dealloc Méthode peut le relâcher lorsque l'objet est détruit.

  • Si vous avez besoin de créer le tableau, puis Retour it à partir de la méthode, vous avez découvert la raison pour laquelle l'aération a été inventée. L'appelant de votre méthode n'est pas responsable de la libération de l'objet, car ce n'est pas un +alloc, +new, -copy, ou -mutableCopy Méthode, mais vous devez vous assurer que cela est publié éventuellement. Dans ce cas, appelez manuellement -autorelease sur l'objet avant de le retourner. Par exemple:

    - (NSArray *)myMethod {
        NSArray *removals = [NSArray new];
        // ...
        return [removals autorelease];
    }
    

Lorsque vous créez le tableau via +arrayWithCapacity:, vous n'appelez pas l'une des méthodes "spéciales", vous n'avez donc pas à relâcher le résultat. Ceci est probablement mis en œuvre avec -autorelease, un peu comme le dernier exemple ci-dessus, mais pas nécessairement. (Incidemment, vous pouvez également créer une nsmutablarray NsmutablearyRay à vide avec [NSMutableArray array]; La méthode est trouvée dans Nsarray, elle ne s'affichera donc pas dans la documentation sous NsmutableArray, mais elle créera une matrice mutable lorsqu'il sera envoyé à la classe NsmutableArray.) Si vous allez retourner le tableau de votre méthode, vous peut l'utiliser comme sténographie pour [[[NSMutableArray alloc] init] autorelease]- mais c'est juste un raccourci. Dans de nombreuses situations, cependant, vous pouvez créer un objet avec -init ou +new et le libérer manuellement au moment opportun.

65
John Calsbeek

Voici comment les choses mises en œuvre derrière la scène:

+(NSMutableArray*) new
{
    return [[NSMutableArray alloc] init];
}

et

+(NSMutableArray*) arrayWithCapacity:(NSNumber)capacity
{
    return [[NSMutableArray alloc] initWithCapacity:capacity] **autorelease**];
}

Dans le premier cas, la matrice n'est attribuée que et vous êtes responsable de la désaffectation. Au contraire, la turywithcapacity a une autorité ajustée pour vous et ne causera pas de fuites, même si vous oubliez de traiter.

7
Tuan

Le cacao utilise certaines conventions de dénomination. Tout ce qui commence par ALLOC, NOUVEAU ou COPY retourne quelque chose avec un retenuCount de 1 et vous devez libérer. Toute autre chose qu'une fonction revienne a une retenue de retenue équilibrée (elle pourrait être détenue par autre chose, ou peut être conservée et sortie).

Donc:

NSMutableArray *removals = [NSMutableArray new];

A une compteur de retenue de 1, et:

NSMutableArray *removals = [NSMutableArray arrayWithCapacity:99];

ou

NSMutableArray *removals = [NSMutableArray array];

Depuis que les méthodes ne sont pas préfixées avec ALLOC, NOUVEAU OU COPIE. Tout cela est épelé dans la gestion de la mémoire Documentation . En particulier:

Vous prenez la propriété d'un objet si vous le créez à l'aide d'une méthode dont le nom commence par "ALLOC" ou "Nouveau" ou contient "Copier" (par exemple, ALLOC, NEWObject ou MutaBrecopy), ou si vous l'envoyez un message de retenue. Vous êtes responsable de la renonciation de la propriété des objets que vous possédez à l'aide de la libération ou de l'autorelease. Toute autre fois que vous recevez un objet, vous ne devez pas la libérer.

4
Louis Gerbarg