2

Lorsqu'une méthode d'instance renvoie une valeur initialisée avec un constructeur de commodité, dois-je conserver cet objet puis auto-libérer dans le retour afin que lorsque la libération automatique du constructeur de commodité se produise, Ne retirez pas l'objet.Retour d'un objet initialisé par le "constructeur de commodité"

Est-ce que cette description de publication avant le code appelant et prendre possession d'un conservateur ou quelque chose?

- (NSStringMutable *)test { 
    NSMutableString *description = [NSMutableString stringWithString:@"Test Value"]; 
    return description; 
} 

Ou devrait-il être comme ça?

- (NSStringMutable *)test { 
    NSMutableString *description = [NSMutableString stringWithString:@"Test Value"]; 
    [description retain];        
    return [description autorelease]; 
} 

Indicatif téléphonique:

NSMutableString *testVar = [[NSMutableString alloc] initWithString:[object description]]; 

Répondre

9

Non, vous devriez être bien avec:

- (NSStringMutable *)test 
{ 
    return [NSMutableString stringWithString:@"Test Value"]; 
} 

Cela laissera l'objet d'un comptage de conserver 1 et sera dans la piscine autorelease.

Le bassin de libération automatique est drainé à des moments précis - ce n'est pas comme un éboueur. Si vous implémentez un gestionnaire d'événements (comme un gestionnaire cliqué sur un bouton), le pool autorelease est drainé par le framework lorsque vous revenez de votre code de gestion d'événements.

Si vous aviez utilisé ceci:

- (NSStringMutable *)test 
{ 
    NSMutableString *description = [NSMutableString stringWithString:@"Test Value"]; 
    [description retain];                
    return [description autorelease]; 
} 

... alors l'objet aurait un compte de 2 conserver et serait dans la piscine autorelease deux fois, et se comporterait en fait de la même manière que dans le exemple de code précédent.

+0

+1 Cela répond à la question – Abizern

+2

Vous avez raison, mais essayez d'éviter de parler des comptes, ils sont un faux-fuyant - il n'y a aucune garantie que NSMutableString retournera un objet autoreleased, seulement qu'il renvoie une chaîne mutable que vous ne possède pas actuellement. Vous pouvez retourner le résultat à votre invocateur simplement parce que les règles de gestion de la mémoire indiquent explicitement que "cette méthode peut également renvoyer l'objet à son invocateur en toute sécurité".

+2

C'est un bon point. Je trouve que penser en termes de comptes de retenue est pratique pour expliquer les choses. Vous avez raison - tout ce que vous savez, c'est que stringWithString renvoie un objet appartenant à quelqu'un d'autre. Dans ce cas, puisque NSMutableString a réellement alloué l'objet, c'est la responsabilité de NSMutableString de le libérer. J'ai cependant eu l'impression que ces constructeurs de commodité (constructeurs non-init) renvoient conventionnellement des objets auto-libérés. Je serais surpris si je tombais sur un qui ne se comporte pas comme ça. –

0

Non, vous pouvez simplement retourner la valeur autoreleased. La raison en est que l'autorelease n'est pas une fonction de la variable elle-même, c'est une fonction du pool autorelease, qui (sauf si vous en créez un vous-même) est généralement géré par la boucle d'exécution.

0

Vous êtes proche de la seconde, mais vous n'avez pas besoin de la retenue pour le cas dont vous parlez ici et en fait, vous n'avez pas besoin d'appeler autorelease vous-même.

Ceci est valable, car stringWithString retourne un objet autoreleased déjà:

- (NSStringMutable *)test 
{ 
    return [NSMutableString stringWithString:@"Test Value"];   
} 

En général lors de la création d'objets en utilisant Objective-C si vous appelez un constructeur de commodité (ne pas appeler alloc et init) la valeur de retour est toujours autoeleased alors stringWithString renvoie un objet autoreleased que vous pouvez simplement retourner.

1

Vous pouvez simplement le retourner. C'est l'un des principaux objectifs de autorelease. À moins que vous n'ayez configuré votre propre pool d'autorelease, le pool ne sera pas drainé avant la prochaine boucle d'événement. Le memory management programming guide explique tout cela dans les moindres détails - vous devriez le lire jusqu'à ce que vous vous en sentiez à l'aise. Note marginale: Si cette n'était pas sécuritaire et que le groupe autorelease allait être drainé tôt pour une raison bizarre, en lui donnant deux retenues et deux autoreleases ne feraient pas de différence. Les chiffres sont toujours équilibrés, de sorte qu'il va encore sortir de l'existence à un moment donné.

1

Je l'ai déjà voté sur la bonne réponse, j'ajoute cela comme une note de style:

Votre code d'appel ne va pas travailler, parce qu'il appelle [object description] quand il devrait appeler [object test]

Vous n'avez pas besoin de renvoyer des chaînes mutables à moins que vous ne souhaitiez vraiment pouvoir modifier la chaîne. J'essaie personnellement de minimiser la mutabilité dans le code que j'écris parce que je pense qu'il est plus facile de maintenir des programmes où les changements d'état sont minimes. Vous ne renvoyez qu'une description, donc je ne pense pas qu'elle doive être modifiable. Je sais que ce n'est que quelques exemples de code alors peut-être que je suis trop pointilleux

Vous pouvez réécrire ce que:

-(NSString *)description { 
    // Just return a static NSString. No need to worry about memory management. 
    return @"Test Value"; 
} 

Et si vous voulez être en mesure de changer la valeur de ce retour chaîne dans votre code d'appel:

NSMutableString *testVar = [[NSMutableString alloc]initWithString:[object description]]; 

Puisque vous avez appelé alloc sur cette chaîne, vous possédez et sont responsables de le libérer à une date ultérieure.

Vous pouvez également utiliser l'un de mes morceaux préférés de code:

NSMutableString *testVar = [[object description] mutableCopy]; 

Ceci renvoie une copie mutable de même un objet immuable (si elle est conforme au protocole NSMutableCopying, bien sûr). Et vous devez envoyer [testVar release] à un certain stade.

Et pour lier cela en tant que réponse réelle à votre question: si vous envoyez alloc, copie, mutableCopy ou conserver à un objet, vous possédez l'objet et que vous êtes responsable de l'envoi c'est un message version. Vous pouvez supposer que toute autre chose renvoie un objet autoreleased. Encore une fois, je sais que ce n'est qu'un petit échantillon de code sur lequel vous avez posé une question, mais si vous suivez la règle ci-dessus, la plupart de vos problèmes de gestion de la mémoire sont triés. Dans votre premier exemple, vous n'en avez envoyé aucun pour les messages, vous n'avez donc pas besoin de libérer de la mémoire vous-même. Cependant, vous avez un alloc dans votre code d'appel, donc vous possédez testVar et vous devez le libérer.

+0

Merci pour l'entrée. Je ne savais pas à propos de mutableCopy.Vous avez raison de dire que c'est juste un exemple pour le but de ma question. Merci pour l'élaboration. Je suis assez nouveau pour l'objectif c, et je n'avais même pas besoin de retourner un NSString que je peux passer à un initWithString pour un NSMutableString. Merci pour l'info. – Brian

Questions connexes