trouver d'ou provient EXC_BAD_ACCESS
Bonjour a tous !
J'ai une erreur de EXC_BAD_ACCESS qui me pose problème déjà comment savoir qui provoque ce problème ?
C'est très bizzare j'ai une boucle qui appelle 10 fois une fonction
Ici aucun problème [self newLocationUpdate:mycurrent_postion] ; ne pose pas de problème
En revanche quand j'appelle la fonction depuis location controller (le delgate qui détecte les changements de position GPS)
j'appelle la fonction exactement de la même manière
Et a ce moment la j'ai un EXC_BAD_ACCESS
d'ou ca peut provenir ? et comment savoir ce qui pose problème
J'ai une erreur de EXC_BAD_ACCESS qui me pose problème déjà comment savoir qui provoque ce problème ?
C'est très bizzare j'ai une boucle qui appelle 10 fois une fonction
for (int x = 0; x < 10; x++){
NSMutableArray * mycurrent_postion = [[[NSMutableArray alloc] initWithCapacity:3] autorelease];
[ mycurrent_postion addObject: [NSString stringWithFormat:@4.88811] ];
[ mycurrent_postion addObject: [NSString stringWithFormat:@4.88811] ];
[ mycurrent_postion addObject: [NSString stringWithFormat:@11188811] ] ;
[self newLocationUpdate:mycurrent_postion] ;
}
Ici aucun problème [self newLocationUpdate:mycurrent_postion] ; ne pose pas de problème
En revanche quand j'appelle la fonction depuis location controller (le delgate qui détecte les changements de position GPS)
j'appelle la fonction exactement de la même manière
current_postion = [[[NSMutableArray alloc] initWithCapacity:4] autorelease];
[ current_postion addObject: [NSString stringWithFormat:@4.88811] ];
[ current_postion addObject: [NSString stringWithFormat:@4.88811] ];
[ current_postion addObject: @222222222] ;
// Send the update to our delegate
[self.delegate newLocationUpdate: current_postion];
Et a ce moment la j'ai un EXC_BAD_ACCESS
d'ou ca peut provenir ? et comment savoir ce qui pose problème
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Est-ce que dans ce cas [tt]newLocationUpdate:[/tt] est appelé ou pas ?
Je soupçonne que ce soit le "self.delegate" qui provoque le BAD_ACCESS, vu que c'est la seule différence...
Il se trouve que j'ai une valeur
lastGetTagsPosition = [[[NSArray alloc] initWithArray:current_position] autorelease];
Je met dans un nouvel array le contenu d'un mutable array nommé current_position.
Quand je li cet array la première fois pas de problème mais quand je le lis une deuxième fois c'est la mort
Pourtant je ne modifie pas mon tableau je fais que le lire et quelques fois le reafecter (mais pas avant que ca bug)
comment est-ce possible ?
Tu lui propose d'écrire alloc+init+retain ?
A la limite je lui aurais bien suggéré au lieu de rendre son objet autorelease de le releaser à la main (alloc+init, puis appel à son [tt]newLocationUpdate:[/tt], puis release), ça évite de garder inutilement des objets en mémoire et laisser l'autoreleasepool gérer, autant gérer nous même quand on peut surtout à l'intérieur des boucles (ou alors créer une autre AutoreleasePool dans la boucle mais pour ce qu'il fait ça vaut pas le coup)
Mais un retain à la place de l'autorelease...
Non déjà de virer le alloc qui, à mon humble avis, n'est pas nécessaire.
Donc en gros de faire NSArray arrayWithArray: + un retain.
Disons que pour moi c'était clair dans ma tête donc j'ai pas proposé le arrayWithArray J'utilise jamais les alloc avec ça.
arrayWithArray est l'exact équivalent de alloc+initWithArray+autorelease. Donc c'est un objet "temporaire" déjà autoreleasé. Tu n'as pas à le retenir avec un "retain" en plus dans le code que l'on voit là (dans la méthode qui crée le array donc), ou alors il faut le balancer avec un "release" dans la même méthode, sinon ça n'a pas trop de sens.
Par contre (et c'est peut-être ça que tu voulais dire ?), c'est peut-être dans la méthode [tt]newLocationUpdate:[/tt] qu'il faut faire le retain (ça dépend si tu yodark garde le paramètre passé ou se contente de s'en servir pour extraire les données et n'en n'a plus besoin ensuite).
yodark, on peut voir à quoi ressemble le code de ton [tt]newLocationUpdate:[/tt] ? Si c'est un "setter" ou qu'il fait appel à un "setter" (donc stocke la variable passée en argument dans une variable de ta classe), il faut bien évidemment réspecter les règles de base des setters (faire un retain sur l'argument, et un release sur la valeur précédemment stockée). --> voir chez Apple pour les détails et exemples de comment bien coder les setters.
(Ou sinon tu peux utiliser les @property de l'Objective-C 2.0)
Voilà , du coup c'est peut-être de ce côté là que ça pêche, tu gardes peut-être de côté cette valeur que tu passes, mais tu oublies de faire un retain alors que tu veux l'utiliser plus tard...
Pour te faire un exemple à la con :
Header :
Implementation :
Et là le log va te sortir un beau
Donc pour moi le retain semble souvent nécessaire, mais bien sûr qu'il ne sert à rien si on compte utiliser la array juste dans le code où on l'initialise.
Tu le dis toi même à la fin de ton post :
C'est exactement ce que je me tue à expliquer ou alors je me suis mal exprimé
Dans ce cas, bien sûr qu'il faut retenir array...
Mais tu oublies de la releaser dans le dealloc...
Oui tu t'es mal exprimé. Car la solution que tu proposes n'est pas la bonne :P Enfin si, dans ton cas de figure particulier, où ta variable est une variable d'instance de ta classe...
La solution qu'il faut adopter c'est d'avoir un bon setter codé comme il faut dans les règles de l'art. Et c'est lui fait le retain sur les variables d'instance de ta classe.
Tu n'as pas à faire de retain sur les variables internes à ta fonction ou variables temporaires.
Donc c'est pas tant le [tt]mycurrent_postion[/tt] (qu'il crée à l'intérieur de sa boucle for, donc variable locale) qu'il faut "retenir", mais la variable d'instance qu'il a déclaré dans sa classe et qu'il affecte avec cette nouvelle valeur, j'imagine dans son code [tt]newLocationUpdate:[/tt] (je ne peux qu'imaginer pour cette partie là puisqu'il ne nous a rien fourni là dessus).
Dans ton code EagleLouk, la seule différence qu'il y a c'est que "array" est une variable de classe, et non pas une variable locale à ta fonction awakeFromNib ou click.
Dans le code de yodark sur lastGetTagsPosition semble être, j'imagine, une variable de la classe et non une variable locale (enfin je ne peux qu'imaginer). Si c'est bien le cas en effet il drait enlever le "autorelease". Par contre pas besoin de faire de retain (bon sauf si tu utilises arrayWithArray qui est fait pour créer des objets temporaires déjà autoreleasés mais je vois pas l'intérêt dans ce cas si c'est pour faire un retain après). Mais penser à faire un "release" de l'ancien objet si lastGetTagsPosition risque d'en contenir un (ce qui n'est pas le cas dans un awakeFromNib qui n'est appelé qu'une fois, mais peut être le cas si lastGetTagsPosition est amené à changer souvent).
Bref, le plus simple c'est de faire un beau setter en suivant les indications dans la page d'Apple que j'ai donnée en lien plus haut. Faire un release de l'ancienne valeur s'il y en a une, puis faire un retain sur current_position (ou alloc+initWithArray comme tu le fais mais bon autant garder le même objet plutôt que d'en créer un clone).
Yodark, tu peux peut-être nous copier le code de ta méthode [tt]newLocationUpdate:[/tt] qu'on te la corrige ? Si elle ne fait que l'affectation (et dans ce cas un nom de setter plus dans les règles de codage aurait été mieux choisi mais passons), alors elle pourrait ressembler donc à ceci : Et là plus de soucis.
Ce n'est qu'un détail, pour montrer ce que je voulais dire ça me semblait pas nécessaire de le présenter dans le post ce dealloc.
[size=15pt]Il est interdit de fumer dans ce forum[/size]
De plus, sur ton code je ne mettrais pas de retain, mais plutôt
Parce que créer un objet autoreleasé pour le retenir aussitôt, c'est un peu gâcher...
Et bien écoute Antilog, Ali m'a fait un beau cours sur les mémoires et j'y vois plus clair en effet.
En fait c'est juste avec les array que je me plantais, et heureusement sinon je vous dis pas tous les codes dégeux que j'ai du faire si ça avait été plus oO
Donc pour moi, Yodark, il suffit simplement d'enlever l'autorelease.
@synthesize current_position
et ensuite je release
current_position à la fin
Je sais pas si c'est juste mais ça semble fonctionner ainsi ! Y a t-il des erreur au niveau de la mémoire?
Merci pour le lien d'apple pour bien coder les setters. Il faut d'abord releaser en mémoire avant de réaffecter ?