Question

Je suis nouveau dans le code géré par la mémoire mais je comprends très bien l'idée.

En prenant mon application à l'aide de l'outil de gestion des fuites dans XCode, j'ai remarqué que je n'avais qu'à nettoyer mes objets personnalisés, mais pas de tableaux créés de manière dynamique par exemple. J'ai donc pensé que ces types de données sont autoreleased. libère les tableaux que j'ai utilisés en tant que propriétés qui avaient un (conserver) sur eux.

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

NSMutableArray *removals = [NSMutableArray new];

mais pas semblable

NSMutableArray *removals = [NSMutableArray arrayWithCapacity:9];

Maintenant, la raison pour laquelle on a été configuré avec " new " Est-ce qu'il pourrait contenir 0-99 éléments, alors que l'autre que je savais allait toujours être 9. Puisque les deux tableaux sont passés à la même méthode plus tard, en fonction de l'interaction utilisateur, j'étais en train de me faire fuir si je ne le faisais pas libérer à la fin de la méthode, ou une exception si je faisais!

J'ai changé le premier tableau en

NSMutableArray *removals = [NSMutableArray arrayWithCapacity:99];

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

Était-ce utile?

La solution

Comme indiqué dans le règles de gestion de la mémoire , chaque fois que vous avez créé un objet avec + alloc , + nouveau , -copy ou -mutableCopy , vous le possédez et vous devez le publier à un moment donné. (En fait, + new est simplement un raccourci pour [[MyClass alloc] init] .) Comme vous l'avez noté, la création d'un tableau via [NSArray new] sans le libérer est une fuite de mémoire. Cependant, si vous manipulez cet objet correctement, il est généralement possible de le libérer à un moment donné. Par exemple:

  • Si la méthode qui utilise le tableau est appelée depuis au sein de la méthode qui crée le tableau, vous devriez pouvoir le libérer après l'avoir déjà utilisé. Si la méthode interne doit conserver une référence plus permanente au tableau, elle est alors responsable de l'envoi de -retain et, éventuellement, de -release à l'objet. Par exemple:

    - (void)myMethod {
        NSArray *removals = [NSArray new];
        // ...
        [someObject someOtherMethod:removals];
        [removals release];
    }
    
  • Si vous avez créé le tableau dans une méthode -init pour un objet, la méthode -dealloc peut le libérer lorsque l'objet est détruit.

  • Si vous devez créer le tableau, puis le renvoyer à partir de la méthode, vous avez découvert la raison pour laquelle le décrochage automatique a été inventé. L'appelant de votre méthode n'est pas responsable de la libération de l'objet, car ce n'est pas un + alloc , + nouveau , -copy , ou la méthode -mutableCopy , mais vous devez vous assurer qu'elle sera finalement publiée. Dans ce cas, vous appelez manuellement -autorelease sur l'objet avant de le renvoyer. Par exemple:

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

Lorsque vous créez le tableau via + arrayWithCapacity: , vous n'appelez pas l'un des paramètres "spécial". méthodes, vous n’avez donc pas à publier le résultat. Ceci est probablement implémenté avec -autorelease , un peu comme le dernier exemple ci-dessus, mais pas nécessairement. (Incidemment, vous pouvez également créer un NSMutableArray vide auto-libéré avec [tableau NSMutableArray] ; la méthode est trouvée dans NSArray, elle ne sera donc pas affichée dans la documentation sous NSMutableArray, mais elle créera un fichier mutable. tableau lorsqu’il est envoyé à la classe NSMutableArray.) Si vous retournez le tableau à partir de votre méthode, vous pouvez l’utiliser comme raccourci pour [[[[[NSMutableArray alloc] init] autorelease]] - mais cela est juste un raccourci. Toutefois, dans de nombreuses situations, vous pouvez créer un objet avec -init ou + nouveau et le relâcher manuellement au moment opportun.

Autres conseils

Voici comment les choses se sont déroulées en coulisse:

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

et

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

Dans le premier cas, le tableau est alloué uniquement et vous êtes responsable de sa désallocation. Au contraire, arrayWithCapacity est auto-libéré pour vous et ne causera pas de fuites même si vous oubliez de désallouer.

Cocoa utilise certaines conventions de dénomination. Tout ce qui commence par alloc, new ou copy renvoie quelque chose avec un retentionCount de 1 et vous devez le publier. Tout ce qui est retourné par une fonction a une valeur RetenueCompte équilibré (elle peut être conservée par quelque chose d'autre, ou peut être conservée et publiée).

Donc:

NSMutableArray *removals = [NSMutableArray new];

a un retenuCompte de 1 et:

NSMutableArray *removals = [NSMutableArray arrayWithCapacity:99];

ou

NSMutableArray *removals = [NSMutableArray array];

Ne le faites pas car les méthodes ne sont pas préfixées par alloc, new ou copy. Tout cela est précisé dans la gestion de la mémoire documentation . En particulier:

  

Vous prenez possession d'un objet si vous   créez-le en utilisant une méthode dont le nom   commence par & # 8220; alloc & # 8221; ou & # 8220; new & # 8221; ou   contient & # 8220; copier & # 8221; (par exemple, alloc,   newObject ou mutableCopy), ou si vous   envoyez-lui un message de retenue. Vous êtes   responsable d'abandonner   propriété des objets que vous possédez avec   libérer ou autorelease. N'importe quel autre moment   vous recevez un objet, vous ne devez pas   libérez-le.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top