Question

Si j'ai bien compris, tout élément créé avec une allocation , une nouvelle ou une copie doit être publié manuellement. Par exemple:

int main(void) {
    NSString *string;
    string = [[NSString alloc] init];
    /* use the string */
    [string release];
}

Ma question, cependant, est-ce que cela ne serait pas aussi valable?:

int main(void) {
    NSAutoreleasePool *pool;
    pool = [[NSAutoreleasePool alloc] init];
    NSString *string;
    string = [[[NSString alloc] init] autorelease];
    /* use the string */
    [pool drain];
}
Était-ce utile?

La solution

Oui, votre deuxième extrait de code est parfaitement valide.

Chaque fois que -autorelease est envoyé à un objet, il est ajouté au pool de libération automatique le plus interne. Lorsque le pool est vidé, il envoie simplement -release à tous les objets du pool.

Les pools de libération automatique sont simplement une commodité qui vous permet de différer l'envoi de la libération jusqu'à "plus tard". Ce " plus tard " Cela peut arriver à plusieurs endroits, mais le plus courant dans les applications Cocoa GUI se situe à la fin du cycle de la boucle d’exécution en cours.

Autres conseils

NSAutoreleasePool: drain vs libération

Étant donné que les fonctions drain et release semblent semer la confusion, il peut être utile de le clarifier ici (bien que cela soit couvert dans la documentation . ..).

À proprement parler, dans la perspective globale, drain n'est pas équivalent à release :

Dans un environnement à référence comptée, drain effectue les mêmes opérations que release . Par conséquent, les deux sont équivalentes. Cela signifie que vous ne ne créez pas de pool si vous utilisez drain plutôt que release .

Dans un environnement rempli de déchets, la version est une opération no-op. Ainsi, cela n'a aucun effet. drain , quant à lui, indique au collecteur qu'il doit "collecter si nécessaire". Ainsi, dans un environnement de récupération, l’utilisation de drain aide le système à balayer la collecte.

Comme déjà indiqué, votre deuxième extrait de code est correct.

Je voudrais suggérer une manière plus succincte d'utiliser le pool de libération automatique qui fonctionne sur tous les environnements (comptage de références, GC, ARC) et évite également la confusion entre drain et rejet:

int main(void) {
  @autoreleasepool {
    NSString *string;
    string = [[[NSString alloc] init] autorelease];
    /* use the string */
  }
}

Dans l'exemple ci-dessus, veuillez noter le bloc @autoreleasepool . Ceci est documenté ici .

Non, vous avez tort. La documentation indique clairement que, dans les cas autres que GC, -drain équivaut à -release, ce qui signifie que NSAutoreleasePool ne ne fuira pas .

Ce que j'ai lu d'Apple: "A la fin du bloc de pool de libération automatique, les objets ayant reçu un message de libération automatique à l'intérieur du bloc reçoivent un message de libération. Un objet reçoit un message de libération à chaque fois qu'un message de libération automatique est envoyé dans le bloc."

https://developer.apple. com / bibliothèque / mac / documentation / cacao / conceptuel / MemoryMgmt / Articles / mmAutoreleasePools.html

envoyer autorelease au lieu de relâcher sur un objet prolonge la durée de vie de cet objet au moins jusqu'à ce que le pool lui-même soit vidé (il peut être plus long si l'objet est conservé ultérieurement). Un objet peut être placé dans le même pool plusieurs fois, auquel cas il reçoit un message de libération pour chaque fois qu'il a été placé dans le pool.

Oui et non. Vous finiriez par libérer la mémoire de la chaîne mais "fuyant". l'objet NSAutoreleasePool en mémoire à l'aide de drain au lieu de relâchement si vous l'avez exécuté dans un environnement mal géré (non géré par la mémoire). Cette " fuite " rend simplement l'instance de NSAutoreleasePool " inaccessible & comme n'importe quel autre objet sans pointeur fort sous GC, et l'objet sera nettoyé la prochaine fois que GC s'exécutera, ce qui pourrait très bien se faire directement après l'appel de -drain :

  

drainer

     

Dans un environnement garbage collect, déclenche un garbage si la mémoire allouée depuis la dernière collecte est supérieure au seuil actuel. sinon se comporte comme une libération.   ...   Dans un environnement de récupération, cette méthode appelle finalement objc_collect_if_needed .

Sinon, cela ressemble à la façon dont -release se comporte en non GC, oui. Comme d'autres l'ont déjà dit, -release est un no-op sous GC. Le seul moyen de s'assurer que le pool fonctionne correctement sous GC est d'utiliser -drain et -drain sous non-GC fonctionne exactement comme -release sous non-GC, et communique sans doute plus clairement ses fonctionnalités.

Je dois signaler que votre déclaration "tout ce qui est appelé avec new, alloc ou init" ne doit pas inclure " init " (mais doit inclure "copie"), car "init" n'alloue pas de mémoire, il ne configure que l'objet (à la manière du constructeur). Si vous avez reçu un objet alloc'd et que votre fonction a uniquement appelé init en tant que telle, vous ne le publieriez pas:

- (void)func:(NSObject*)allocd_but_not_init
{
    [allocd_but_not_init init];
}

Cela ne consomme pas plus de mémoire que celle avec laquelle vous avez déjà commencé (en supposant que init n'instancie pas les objets, mais vous n'en êtes pas responsable, de toute façon).

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