autorelease précoce
chaps31
Membre
Bonjour à tous,
J'ai un soucis bizarre. Une méthode retourne un nsarray, juste avant le "return" je fais un [monArray autorelease];
Rien d'extraordinaire, sauf que j'ai alors un erreur d'accès mémoire... Normalement c'est comme cela que l'on fait non ? Avec l'autorelease, le release devrait avoir lieu "qu'un peu plus tard" non ?
Merci
J'ai un soucis bizarre. Une méthode retourne un nsarray, juste avant le "return" je fais un [monArray autorelease];
Rien d'extraordinaire, sauf que j'ai alors un erreur d'accès mémoire... Normalement c'est comme cela que l'on fait non ? Avec l'autorelease, le release devrait avoir lieu "qu'un peu plus tard" non ?
Merci
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Le problème est ailleurs, montre-nous ton code.
Comment Alloues-tu ton NSArray ?
Est-ce avec un [[NSArray alloc] Init ....?
Ou avec un constructeur de commodité genre [NSArray arrayWith... ?
Par ce que dans le premier cas t'as un objet avec un retainCount à 1 (que tu peux (doit?) autoreleaser)
Dans l'autre cas t'as un objet déjà autoreleasé et donc, ne surtout pas le releaser en plus.
Sinon t'as raison, pour une valeure de retour d'une méthode, la convention des méthodes veut que les valeurs de retour soit autoreleasées...
Et justement cette méthode, si elle est faite dans les règles de l'art, te retourne un objet "autoreleasé" donc ne pas y ajouter un autorelease de plus mal venu ....
Je plussoie.
Si je mets l'autorelease à l'emplacement indiqué, PAF "EXEC_BAD_ACCESS"...
Des méthodes de 3 lignes :
Ligne 1 alloc init
Ligne 2 appel à la méthode dont je parle dans ce threat qui retourne une valeur prise par l'objet de la ligne 1
ligne 3 retour de la valeur prise par l'objet de la ligne 2
Ben dès que je met un autorelease que ce soit juste avant le return ou bien sur la ligne du alloc init j'ai un soucis, message d'erreur, ou encore compilation interminable qui bloqie mon macbook...
Ou bien est-ce ça qui est correct :
- Tu alloues un NSMutable array
- Tu perds la référence -> leak
Tu veux dire qu'un espace mémoire est alloué lors de l'alloc init, mais aussi à la deuxième ligne ?
Bah à la 2e ligne je ne sais pas ce que fait ta fonction, mais en tout cas l'espace mémoire alloué à la première ligne est perdu à tout jamais...
Ou comme si tu faisais en PHP ou JS ou autre, genre [tt]t = new Array();[/tt] puis [tt]t = retourneTableau();[/tt], la valeur retournée par retourneTableau remplace la précédente valeur, donc le précédent tableau créé par [tt]new Array()[/tt], ce tableau créé par new Array ne sert donc à rien puisqu'il n'est jamais utilisé et immédiatement remplacé et donc perdu !
Je ne sais pas si on peut créer un leak avec... mais en tout cas on peut faire un peu n'importe quoi.
C'est prévu pour eviter le problème. De même que les variables sont très peux typé ! C'est pas le langage le plus approprié pour apprendre à gérer la mémoire.
PS : question HS : comment supprimer un mot ajouté dans le dictionnaire de FireFox par erreur ?
Toute ces histoires me font me poser une question.
Soit une variable d'instance d'une de mes classes :
NSMutableArray *maVar;
Dans mon code écrire juste :
maVar=[unReceveur methodeRetournantUnTableau];
Suffit
Pas besoin de alloc init.
tout autant que pour une variable propre à une méthode, je peux écrire.
NSString *maString;
maString=[nReceveur methodeRetournantUnString];
Pas de alloc Init
D'ailleurs on écrit généralement ça en une ligne :
Du coup "villes" étant un tableau variable d'instance de ma classe :
Avec eraseRedond qui vire du tableau les doublons,c'est pas terrible, vaut mieux que eraseRedond ne renvoie rien (void), il modifie ce que je lui passe (la variable d'instance) et je réécris :
Cependant la grande nuance entre une variable d'instance et une variable propre à une méthode, c'est que la variable d'instance elle existe pendant toute la durée de vie de l'objet, là où la variable propre à la méthode n'existe que dans le contexte du bloc de ta méthode et n'est plus accédee après.
Du coup, si tu respectes les règles, normalement [tt][unReceveur methodeRetournantUnString][/tt] est sensé te retourner un objet autoreleased, que tu stoques dans maVar ou maString... oui mais un objet autoreleased est relâché "plus tard"... c'est à dire plus précisément à la fin de la runloop.
Ca va très bien pour des objets créés dans ta méthode, et passés de main en main dans les méthodes appelantes ou appelées, jusqu'à ce que toute la chaà®ne des méthodes consécutives à ton événement (un tap/clic sur un bouton, une méthode de delegate, ou autre, qui a son tour a généré tous les appels de méthodes etc). Mais pour une variable d'instance, le but de ces dernières étant de stocker des objets/variables pendant toute la vie de l'objet/l'instance... là par contre tu es sensé pouvoir y accéder plus tard aussi.
Et si tu les gardes en "autorelease", elles vont être détruites bien trop tôt.
Conclusion, pour les variables d'instances, il faut garder les objets que tu mets dans ces variables d'instance en mémoire tant que l'instance en question existe. Donc par exemple pour les variables d'instance que tu initialises dès la création de ton objet, dans le init / initWithCoder / initMachinTruc, il faut que ces variables aient encore un retainCount de 1 à la fin de l'init. Et tu équilibre avec un release, certes, mais dans le -(void)dealloc de ta classe, qui est un peu le pendant / symétrique du "dealloc", si tu veux. Si ce sont des variables que tu n'initialises que plus tard, ça ne change rien, il faut pour ces variables d'instance faire le release dans le dealloc (si la variable n'a jamais eu l'occasion d'être initialisée pendant la durée de vie de l'objet, tu enverras alors un release à un objet "nil", ce qui n'a aucune conséquence, et si ça a été initialisé à un objet dont le retainCount est donc à 1, ça va bien le libérer.
D'après les conventions de nommage, soit tu appelles ta méthode "arrayWithDuplicatedRemoved" ou un truc comme ça, qui, comme son nom commence par "array..." mentionne que ça retourne un nouveau tableau autoreleased, soit tu gardes le nom "eraseRedond" ou "eraseDuplicates" mais alors d'après le nom ça effectue l'action d'effacer les doublons... sur l'objet courant, sans en retourner un nouveau mais bien en modifiant l'objet.
Bon, maintenant, pour des collections n'ayant pas la vocation d'avoir des doublons, plutôt qu'utiliser un NSArray tu pourrais voir si ça ne vaut pas le coup d'utiliser un NSSet (un "set" = un "ensemble" (y compris au sens mathématique du terme = collection sans ordre et sans doublon). C'est p'tet pas mieux que de supprimer les doublons, selon les méthodes dont tu auras besoin pour manipuler tes villes ensuite (genre si justement tu veux un certain ordre pour ce tableau "villes"), à toi de voir.
Ou sinon aussi un NSDictionary, où les clés sont les noms des villes, et les objets associés peuvent être alors des objets persos de la classe perso "Ville" par exemple, classe contenant toutes les informations d'une ville. Ou alors l'objet associé est ton objet cpVilles (celui dont tu extraits le nom de la ville pour déterminer la clé justement)... Enfin à réfléchir selon ton cas, ce ne sont que des pistes, à toi de voir selon ton usage.
ou là
Là , je dirais que t'as pas compris le rapport de clang :P
J'ai connu quelqu'un qui avait un problème d'Autorelease précoce.
Il a été voir un psychiatre (psy-sexologue) et depuis sa femme est très épanouie
:)beta:
Me cherchez pas, je suis déjà sorti
La forme, le toubib... :kicking: ;D
Ha... je me demandais qui allait rebondir sur le titre
Pour clang je vois "Leak" je pense fuite mémoire ce qui semblait se confirmer à d'autres endroits du code.
Qui apparaà®t ligne 121, l'allocation litigieuse se situe au dessus, ligne 117 de mon code de l'AppDelegate.
Et c'était le dernier endroit de la méthode où je les utilisais, comme quoi quand Schlum dit un truc...