trouver d'ou provient EXC_BAD_ACCESS

yodarkyodark Membre
14:47 modifié dans API UIKit #1
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

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




Réponses

  • AliGatorAliGator Membre, Modérateur
    14:47 modifié #2
    T'as vérifié en pas à  pas, en mettant un breakpoint pour voir exactement à  quelle ligne ça plantait ?
    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...
  • yodarkyodark Membre
    14:47 modifié #3
    Après de longue heures de debboggage j'ai trouvé le problème
    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
    NSLog(@&quot;lastgettag postion %@ &#092;n&#092;n&quot;,[lastGetTagsPosition objectAtIndex:0]);
    


    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 ?
  • 14:47 modifié #4
    remplace l'autorelease par retain.
  • AliGatorAliGator Membre, Modérateur
    14:47 modifié #5
    dans 1223906883:

    remplace l'autorelease par retain.
    Hein ??! C'est quoi cette proposition ?
    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...
  • 14:47 modifié #6
    dans 1223907701:

    dans 1223906883:

    remplace l'autorelease par retain.
    Hein ??! C'est quoi cette proposition ?
    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 :D J'utilise jamais les alloc avec ça.
  • AliGatorAliGator Membre, Modérateur
    14:47 modifié #7
    Reste que je ne comprends toujours pas ton "retain" que tu suggères...

    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...
  • octobre 2008 modifié #8
    Oui mais moi de mon côté si je mets pas de retain je peux pas utiliser la array dans une autre partie de mon code  :o

    Pour te faire un exemple à  la con :

    Header :
    <br />@interface AppC : NSObject {<br />	NSArray* array;<br />}<br />- (IBAction)click:(id)sender;<br /><br />@end
    


    Implementation :
    <br />@implementation AppC<br /><br />- (void)awakeFromNib<br />{<br />	array = [NSArray arrayWithObjects:@&quot;Lol&quot;,@&quot;Lol&quot;,nil];<br />	<br />}<br />- (IBAction)click:(id)sender<br />{<br />	NSLog(@&quot;%@&quot;,[array objectAtIndex:0]);<br />}<br />
    


    Et là  le log va te sortir un beau

    2008-10-13 18:38:50.064 Test[509:10b] *** -[NSWorkspace objectAtIndex:]: unrecognized selector sent to instance 0x135560


    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 :

    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.

    C'est exactement ce que je me tue à  expliquer :D ou alors je me suis mal exprimé
  • AntilogAntilog Membre
    14:47 modifié #9
    Ca n'a rien que de très normal, tu utilises ton array comme variable d'instance de ta classe!
    Dans ce cas, bien sûr qu'il faut retenir array...
    Mais tu oublies de la releaser dans le dealloc...
  • AliGatorAliGator Membre, Modérateur
    octobre 2008 modifié #10
    Ah ben voilà , c'est donc ce dont je parle.
    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 = [[[NSArray alloc] initWithArray:current_position] autorelease];
    
    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 :
    -(void)newLocationUpdate:(NSArray*)newPos<br />{<br />&nbsp; if (lastGetTagsPosition&nbsp; != newPos)<br />&nbsp; {<br />&nbsp; &nbsp; [lastGetTagsPosition release]; // relacher l&#39;ancien objet<br />&nbsp; &nbsp; [newPos retain]; // retenir le nouvel objet<br />&nbsp; &nbsp; lastGetTagsPosition&nbsp; = newPos;<br />&nbsp; }<br />}
    
    Et là  plus de soucis.
  • 14:47 modifié #11
    dans 1223916749:

    Mais tu oublies de la releaser dans le dealloc...


    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.
  • AntilogAntilog Membre
    14:47 modifié #12
    Oui, mais il n'empêche...

    [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
    - (void)awakeFromNib<br />{<br />	array = [[NSArray alloc] initWithObjects:@&quot;Lol&quot;,@&quot;Lol&quot;,nil];<br />	<br />}
    


    Parce que créer un objet autoreleasé pour le retenir aussitôt, c'est un peu gâcher...
  • 14:47 modifié #13
    dans 1223928756:

    Oui, mais il n'empêche...

    [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
    - (void)awakeFromNib<br />{<br />	array = [[NSArray alloc] initWithObjects:@&quot;Lol&quot;,@&quot;Lol&quot;,nil];<br />	<br />}
    


    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.
  • yodarkyodark Membre
    octobre 2008 modifié #14
    j'ai bricolé de la manière suivante :

    @synthesize ; current_position

    <br />-(void)newLocationUpdate:(NSMutableArray *)myCurrent_position {<br />current_position = myCurrent_position;<br />	<br />	[self receiveGPSData];<br />	<br />	<br />	}
    


    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 ?

    - (void) setTitle: (NSString*) newTitle<br /><br />{<br /><br />&nbsp; &nbsp; if (title != newTitle) {<br /><br />&nbsp; &nbsp; &nbsp; &nbsp; [title release];<br /><br />&nbsp; &nbsp; &nbsp; &nbsp; title = [newTitle retain]; // or copy depending on your needs<br /><br />&nbsp; &nbsp; }<br /><br />}
    


Connectez-vous ou Inscrivez-vous pour répondre.