Crash sur NSUserDefaults

allianallian Membre
juin 2009 modifié dans API UIKit #1
Bonjour,
j'ai un petit soucis avec NSUserDefaults je pense, en effet je fais une comparaison pour voir certaines valeurs préalablement sauvegardées dans ce dernier. Tout marche trés bien pendant un ou deux appels mais parfois cela plante, soit sans erreurs soit des fois j'ai ça Program received signal:  “EXC_BAD_ACCESS”.
Avec le objc_msg_send sur la ligne où justement je fais mon if avec les NSUserDefaults.

Quelqu'un à  t il une idée ?
Voici mon code

NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];<br />	BOOL conditionsBool = [standardUserDefaults boolForKey:@&quot;conditions&quot;];<br />	NSLog([standardUserDefaults objectForKey:@&quot;mail&quot;]);<br />	NSLog([standardUserDefaults objectForKey:@&quot;login&quot;]);<br />	<br />	if ([[standardUserDefaults objectForKey:@&quot;mail&quot;] isEqualToString:@&quot;&quot;] &amp; [[standardUserDefaults objectForKey:@&quot;login&quot;] isEqualToString:@&quot;&quot;] | conditionsBool == NO)<br />	{...}


Merci

EDIT : j'ai aussi un soucis étrange, dans un des mes UIViewController j'ai des variables déclarées à  l'extérieur de mes méthodes et parmi elles un tableau que je modifie, hors quand je recommence une partie disons le controlleur me récupere l'ancien tableau alors que je fais bien un release et la création d'un nouveau controleur de la meme classe.


Une idée ?

Réponses

  • AliGatorAliGator Membre, Modérateur
    17:29 modifié #2
    Pour les BAD_ACCESS je sais pas (quoique ça peut être lié ?), mais tes conditions il faut les tester avec des opérateurs logiques, pas binaires. Autrement dit utilise "&&" pour un "ET" et "||" pour le "OU", et non pas "&" et "|" respectivement, qui eux font des opérations bit à  bit et non sur les valeurs logiques YES/NO.
    De plus il est bon de "parenthèser" tes expressions, pour leur mettre des priorités, quand tu mélanges les && et les ||...
  • schlumschlum Membre
    17:29 modifié #3
    Si les "objectForKey" renvoient nil, les NSLog vont crasher...
    Mieux vaut utiliser NSLog(@%@",...)
  • allianallian Membre
    17:29 modifié #4
    Merci pour vos réponses j'ai modifié mes conditions mais cela crash toujours...
    Voila ce que me sort le debugger :

    image7csp.png

    Sinon vous avez pas une idée pour mon tableau qui persiste en mémoire ?
    Je fais cela dans ma classe MyBleeker:

    #import &quot;MyBleeker.h&quot;<br />#import &quot;Labirynthe.h&quot;<br /><br /><br />@implementation MyBleeker<br />@synthesize isBad, myBleeker, myTimer, isStoped, monTimer, theLab, a, b, x , y, counter, directionBleeker, initBallNumber, score, isSimpleTap, myDoubleTapTimer,monTimer2;<br /><br /><br />//&nbsp; &nbsp; &nbsp;  y&nbsp; &nbsp; x<br />int laby[CASES_LARGEUR][CASES_HAUTEUR] = {<br />{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},<br />{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},<br />{1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},<br />{1,1,0,1,1,1,0,1,1,1,1,1,1,0,1,1,0,1,1,1,0,1,0,1},<br />{1,1,0,1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,1},<br />{1,1,0,1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,1},<br />{1,1,0,0,0,1,0,0,0,1,1,1,1,1,1,1,0,0,0,1,0,1,0,1},<br />{1,1,0,0,0,1,0,0,0,1,1,1,1,1,1,1,0,0,0,1,0,1,0,1},<br />{1,1,0,0,0,1,0,0,0,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1},<br />{1,1,0,1,0,1,1,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,0,1},<br />{1,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,1},<br />{1,1,0,1,1,0,1,1,1,1,0,0,0,0,0,1,1,1,0,0,0,1,0,1},<br />{1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1},<br />{1,1,0,0,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,0,1,0,1},<br />{1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},<br />{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}<br />};<br />int labyForEnemies[CASES_LARGEUR][CASES_HAUTEUR] = {<br />{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},<br />{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},<br />{1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},<br />{1,1,0,1,1,1,0,1,1,1,1,1,1,0,1,1,0,1,1,1,0,1,0,1},<br />{1,1,0,1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,1},<br />{1,1,0,1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,1},<br />{1,1,0,0,0,1,0,0,0,1,1,1,1,1,1,1,0,0,0,1,0,1,0,1},<br />{1,1,0,0,0,1,0,0,0,1,1,1,1,1,1,1,0,0,0,1,0,1,0,1},<br />{1,1,0,0,0,1,0,0,0,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1},<br />{1,1,0,1,0,1,1,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,0,1},<br />{1,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,1},<br />{1,1,0,1,1,0,1,1,1,1,0,0,0,0,0,1,1,1,0,0,0,1,0,1},<br />{1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1},<br />{1,1,0,0,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,0,1,0,1},<br />{1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},<br />{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}<br />};<br />int balls[CASES_LARGEUR][CASES_HAUTEUR] = {<br />{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},<br />{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},<br />{1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},<br />{1,1,0,1,1,1,0,1,1,1,1,1,1,0,1,1,0,1,1,1,0,1,0,1},<br />{1,1,0,1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,1},<br />{1,1,0,1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,1},<br />{1,1,0,0,0,1,0,0,0,1,1,1,1,1,1,1,0,0,0,1,0,1,0,1},<br />{1,1,0,0,0,1,0,0,0,1,1,1,1,1,1,1,0,0,0,1,0,1,0,1},<br />{1,1,0,0,0,1,0,0,0,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1},<br />{1,1,0,1,0,1,1,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,0,1},<br />{1,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,1},<br />{1,1,0,1,1,0,1,1,1,1,0,0,0,0,0,1,1,1,0,0,0,1,0,1},<br />{1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1},<br />{1,1,0,0,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,0,1,0,1},<br />{1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},<br />{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}<br />};<br /><br />int l = 2;<br />int c = 2;<br />int phase = 1;<br />
    


    Cette classe est appelé par une autre classe BleekerViewController dans sa méthode viewDidLoad comme cela "monBleeker = [[MyBleeker alloc] init];"

    Et à  chaque partie je fais cela

    BleekerViewController *tmpController = [[BleekerViewController alloc] init];<br />		self.theBleekerViewController = nil;<br />		self.theBleekerViewController = tmpController;<br />		[self.theMenuViewController.view removeFromSuperview];<br />		self.theMenuViewController = nil;<br />		[UIView beginAnimations:@&quot;View Flip&quot; context:nil];<br />		[UIView setAnimationDuration:1.5];<br />		[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];<br />		[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:self.view cache:YES];<br />		[self.view insertSubview:tmpController.view atIndex:0];<br />		[UIView commitAnimations];<br />	<br />		[tmpController release];<br />
    


    Normalement le BleekerViewController est un nouveau à  chaque fois non ?
    Pourquoi mon tableau reste t il en mémoire ?
  • zoczoc Membre
    17:29 modifié #5
    dans 1244020476:

    Sinon vous avez pas une idée pour mon tableau qui persiste en mémoire ?


    Quel tableau ? laby ou labyForEnnemies ou balls ??

    Si oui, alors c'est tout à  fait normal qu'ils persistent, car, n'étant pas déclarés en tant que variables d'instance dans l'interface MyBleeker, ce ne sont rien d'autre que des tableaux statiques en C classique (tout comme les variables l, c et phase, dont le contenu, lui aussi, persiste...

    Les tableaux doivent être déclarés dans l'interface, puis initialisés dans la méthode init de l'implémentation de cette interface. Je crois qu'une petite révision des notions de base d'objective-C s'impose...
  • allianallian Membre
    juin 2009 modifié #6
    Oui c'est bon je les ait initialisé dans une méthode init de ma classe et cela marche très bien maintenant.
    Je suis d'accord sur le fait qu'il soit statiques mais je pensais que du moment ou je releasé ma classe ils était éffacés de la mémoire comme si je quittais mon appli. J'aurais appris quelque chose. Merci

    Par contre j'ai un autre soucis, enfin peut etre ce n'en est pas un.
    Lorsque je Run mon appli la console ne me dit rien de spécial mais lorsque je Run + Debug la console m'affiche ceci :

    Loading program into debugger...<br />GNU gdb 6.3.50-20050815 (Apple version gdb-962) (Sat Jul 26 08:14:40 UTC 2008)<br />Copyright 2004 Free Software Foundation, Inc.<br />GDB is free software, covered by the GNU General Public License, and you are<br />welcome to change it and/or distribute copies of it under certain conditions.<br />Type &quot;show copying&quot; to see the conditions.<br />There is absolutely no warranty for GDB.&nbsp; Type &quot;show warranty&quot; for details.<br />This GDB was configured as &quot;i386-apple-darwin&quot;.warning: Unable to read symbols for &quot;/System/Library/Frameworks/UIKit.framework/UIKit&quot; (file not found).<br />warning: Unable to read symbols from &quot;UIKit&quot; (not yet mapped into memory).<br />warning: Unable to read symbols for &quot;/System/Library/Frameworks/CoreGraphics.framework/CoreGraphics&quot; (file not found).<br />warning: Unable to read symbols from &quot;CoreGraphics&quot; (not yet mapped into memory).<br />Program loaded.<br />sharedlibrary apply-load-rules all<br />Attaching to program: `/Users/extstud7/Library/Application Support/iPhone Simulator/User/Applications/FEB98737-FF99-4774-AF84-0BAEEF37F298/Bleeker.app/Bleeker&#39;, process 3862.<br />
    


    Est ce normal ? C'est la même erreur que lorsque il y a des problèmes de mémoires si je ne me trompe.

    EDIT : un autre indice peut etre, des fois lorsqu'il plante il me dit que l'argument passé à  mon isEqualToString qui devrait etre un NSString issu de mon NSUserDefaults est un CABasicAnimation !! Bizarre surtout que mes NSString n'ont pas bougé entre les deux fois ou j'appelle la méthode.

    Du coup il me dit ça :

    *** -[CABasicAnimation isEqualToString:]: unrecognized selector sent to instance 0x50d200<br />2009-06-03 15:56:15.662 Bleeker[5318:20b] *** Terminating app due to uncaught exception &#39;NSInvalidArgumentException&#39;, reason: &#39;*** -[CABasicAnimation isEqualToString:]: unrecognized selector sent to instance 0x50d200&#39;<br />2009-06-03 15:56:15.663 Bleeker[5318:20b] Stack: (<br />&nbsp; &nbsp; 2520555691,<br />&nbsp; &nbsp; 2530467387,<br />&nbsp; &nbsp; 2520584874,<br />&nbsp; &nbsp; 2520578220,<br />&nbsp; &nbsp; 2520578418,<br />&nbsp; &nbsp; 60682,<br />&nbsp; &nbsp; 60146,<br />&nbsp; &nbsp; 816115430,<br />&nbsp; &nbsp; 816516406,<br />&nbsp; &nbsp; 816517630,<br />&nbsp; &nbsp; 816514372,<br />&nbsp; &nbsp; 816216343,<br />&nbsp; &nbsp; 816148479,<br />&nbsp; &nbsp; 816144864,<br />&nbsp; &nbsp; 827743722,<br />&nbsp; &nbsp; 827753484,<br />&nbsp; &nbsp; 2520057237,<br />&nbsp; &nbsp; 2520059000,<br />&nbsp; &nbsp; 827745792,<br />&nbsp; &nbsp; 827745989,<br />&nbsp; &nbsp; 816114848,<br />&nbsp; &nbsp; 816160924,<br />&nbsp; &nbsp; 10292,<br />&nbsp; &nbsp; 10146<br />)<br />
    


  • zoczoc Membre
    17:29 modifié #7
    dans 1244031848:

    Est ce normal ?

    Tout ce que je vois, ce sont des Warning sans réelle importance pour la stabilité de l'application.

    EDIT : un autre indice peut etre, des fois lorsqu'il plante il me dit que l'argument passé à  mon isEqualToString qui devrait etre un NSString issu de mon NSUserDefaults est un CABasicAnimation !! Bizarre surtout que mes NSString n'ont pas bougé entre les deux fois ou j'appelle la méthode.

    Symptôme typique d'un écrasement mémoire ou de tentative d'accès à  un objet qui a été détruit trop tôt...

  • allianallian Membre
    17:29 modifié #8
    Du coup c'est un release qui intervient trop tot tu pense ?
    Le probleme est que j'essaye d'en mettre le plus possible car l'appli bouffe déjà  16-18Mo de RAM sur mon mac du coup je commence à  avoir peur lorsque je vais la tester sur le device.

    Une chose que je ne comprends pas c'est que dans mes méthodes dealloc je release toutes les propriétés de mes classes mais j'ai l'impression que soit dealloc n'est pas appelé lorsque je fais removeFromSuperview, soit que mes propriétés sont encore retenues après le release.

    Bref je galère un peu avec ces histoires de mémoire...
  • zoczoc Membre
    juin 2009 modifié #9
    dans 1244043839:
    Le probleme est que j'essaye d'en mettre le plus possible

    Déjà , en disant cela, c'est mal parti, car rajouter des retain/release après coup, plus ou moins "au hasard", c'est l'assurance d'avoir des problèmes. Il ne faut pas en "mettre le plus possible", mais il faut en mettre partout ou cela est nécessaire, pas plus, pas moins.

    Bref je galère un peu avec ces histoires de mémoire...

    Ce n'est pas très compliqué, mais cela demande une rigueur extrême. Tant que tout n'est pas entré, il faut relire et relire encore la documentation officielle sur la gestion de la mémoire. La gestion de la mémoire, surtout sur un iPhone qui dispose de peu de mémoire, doit devenir un réflexe.

    Après, c'est évidemment plus facile à  dire qu'à  faire. Mais il existe des outils d'analyse de code source comme clang, qui sont capables de détecter un grand nombre de "mauvaises pratiques". Voir http://www.osx-dev.com/index.php?topic=3296
  • Philippe49Philippe49 Membre
    17:29 modifié #10
    dans 1244043839:

    Une chose que je ne comprends pas c'est que dans mes méthodes dealloc je release toutes les propriétés de mes classes mais j'ai l'impression que soit dealloc n'est pas appelé lorsque je fais removeFromSuperview, soit que mes propriétés sont encore retenues après le release.

    Bref je galère un peu avec ces histoires de mémoire...

    - Mets un NSlog dans ton dealloc, tu verras bien.
    - Utilises l'instrument Leaks
    - Le release/retain est pourtant simple : "Tout ce qui reçoit un retain de vra recevoir un release". En général, c'est celui qui a fait le retain qui fait le release.
  • allianallian Membre
    17:29 modifié #11
    D'après ce que j'ai pu comprendre toutes mes propriétés ayant un retain doivent être releasé dans le dealloc. Ensuite lorsque j'initialise un UIViewController par exemple ici :

    <br />-(void)switchToEnd:(int)theFinalScore {<br />	<br />	WinnerController *tmpController = [[WinnerController alloc] initWithNibName:@&quot;YouWin&quot; bundle:nil];<br />	tmpController.score = theFinalScore;<br />	self.theWinnerViewController = nil;<br />	self.theWinnerViewController = tmpController;<br />	[self.theBleekerViewController.view removeFromSuperview];<br />	[theBleekerViewController release];<br />	self.theBleekerViewController = nil;<br />	[UIView beginAnimations:@&quot;View Flip&quot; context:nil];<br />	[UIView setAnimationDuration:1.5];<br />	[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];<br />	[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:self.view cache:YES];<br />	[self.view insertSubview:tmpController.view atIndex:0];<br />	[UIView commitAnimations];<br />	<br />	[tmpController release];<br />	<br />}
    


    Je dois bien le releasé le tmpController ?? N'est ce pas ?
    Autre exemple les UIAlertView même sans retain doivent être releasé non ?

    Autre exemple ici :

    - (void)viewDidLoad {<br />	<br />	NSBundle * mainBundle=[NSBundle mainBundle];<br />	UIImage * myImage = [[UIImage alloc] initWithContentsOfFile: [mainBundle pathForResource:@&quot;back&quot; ofType:@&quot;png&quot;] ];<br />	UIImageView * imgCard = [[UIImageView alloc] init];<br />	[imgCard setImage:myImage];<br />	[myImage release];<br />	<br />	CGRect frame = self.view.frame;<br />	imgCard.frame = frame;<br />	<br />	[self.view insertSubview:imgCard atIndex:0];<br /><br />	self.view.backgroundColor = [UIColor clearColor];<br />	<br />	[imgCard release];<br />&nbsp; &nbsp; [super viewDidLoad];<br />}<br />
    


    J'effectue bien mes releases là  ?

    Et ici :

    Labirynthe *myLabi = [[Labirynthe alloc] init];<br />	[myLabi copyArray:leLaby];<br />	CGRect frame = self.view.frame;<br />	myLabi.frame = frame;<br />	self.view = myLabi;<br />	self.view.backgroundColor = [UIColor clearColor];<br />
    


    Je fais comment pour releasé, si je dois le faire bien sur, myLabi ? je le fais desuite ou cela se fait tout seul ?

    Ca fais beaucoup de choses d'un coup je sais.
    Merci d'avance
  • allianallian Membre
    17:29 modifié #12
    J'ai utilisé Clang et ça m'a déjà  permis de virer pas mal d'erreurs je pense.
    Après il m'en reste une où il me dit de faire un release sur un objet où j'ai fait un alloc init ce qui est normal mais le probleme est que du coup j'ai un bug dans une NSString qui n'a plus la bonne valeure.

    SpotDetailsDB *SpotDetailsObj = [[SpotDetailsDB alloc] init];<br />	[SpotDetailsObj getInitialDataToDisplay:[appDelegate getDBPath] andSpotId:spotID];<br /><br />	self.title = SpotDetailsObj.name;<br />	nameLabel.text = SpotDetailsObj.name;<br />	descLabel.text = SpotDetailsObj.description;<br />	tideLabel.text = SpotDetailsObj.bestTide;<br />	swellLabel.text = SpotDetailsObj.bestSwell;<br />	windLabel.text = SpotDetailsObj.bestWind;<br />	typeLabel.text = SpotDetailsObj.type;<br />	lat = SpotDetailsObj.lat;<br />	lon = SpotDetailsObj.lon;<br />	<br />&nbsp; &nbsp; [super viewDidLoad];<br />
    


    J'attribue toutes mes valeurs et dans une autre méthode je fais ceci :

    -(void)showPlan:(id)sender {<br />	NSLog(@&quot;%@&quot;,lat);<br />	NSString *infoBulle = [nameLabel.text stringByReplacingOccurrencesOfString:@&quot; &quot; withString:@&quot;+&quot;];<br />	NSString* url = [NSString stringWithFormat:@&quot;http://maps.google.com/maps?q=%@,%@+(%@)&quot;,lat,lon,infoBulle];<br />	[[UIApplication sharedApplication] openURL:[NSURL URLWithString:url]];<br />}
    


    Et les deux nsstring lat et lon n'ont plus la bonne valeure du coup ça plante...
  • AliGatorAliGator Membre, Modérateur
    17:29 modifié #13
    Si lat et long viennent de CoreLocation et d'une structure CLLocation, en particulier sont extraits d'un CLLocationCoordinate2D, les membres de cette structure sont des CLLocationDegrees qui sont en fait des double.

    Donc NSLog(@%@,lat) va planter si lat est un double (alors que %@ attend un objet Cocoa genre NSObject)... Et du coup c'est p'tet simplement ton %@" présent dans ton NSLog et dans ton stringWithFormat qui fait planter ton appli, non ?
  • zoczoc Membre
    juin 2009 modifié #14
    Il faut en effet nous en dire plus sur les variables lat, lon de ta vue et de ton interface SpotDetailsDB. Si ce sont des properties de type NSString* avec l'attribut "retain" ou "copy", alors en écrivant :

    self.lat = SpotDetailsObj.lat;<br />self.lon = SpotDetailsObj.lon;
    


    ou (je déteste la notation "." introduite avec Objective-C 2.0 et personnellement j'écris toujours "à  l'ancienne):

    [self setLat: [SpotDetailsObj lat]];<br />[self setLon: [SpotDetailsObj lon]];
    


    tu devrais pouvoir faire un release sur SpotDetailsObj sans avoir de problèmes par la suite.

    L'autre solution c'est d'écrire :

    lat = [[SpotDetailsObj lat] retain];<br />lon = [[SpotDetailsObj lon] retain];
    


    (Toujours en supposant que toutes les properties en jeu sont de même type, et sont des objets, pas des types C de base).

    Evidemment, si ce n'est déjà  fait, ne pas oublier les release de lat et lon dans la méthode dealloc de la vue.
  • AliGatorAliGator Membre, Modérateur
    17:29 modifié #15
    Sauf que faire [tt]lat = [SpotDetailsObj.lat retain];[/tt] dans ta 2e solution zoc n'est pas suffisant, car si on passe 2 fois dans la même méthode, la 2e fois lat n'est pas nil et tu oublies de le releaser... il faut donc faire un release avant... à  condition que le "SpotFetailsObj.lat" ne soit pas le même que le "lat" déjà  existant... bref c'est pas aussi simple comme cas... Alors que [tt]self.lat = SpotDetailsObj.lat[/tt] fait appel au setter et donc gère automatiquement tous ces petits tracas possibles.

    Donc si c'est une NSString* ou un objet du genre alors c'est ta première solution zoc qu'il faut adopter. Si c'est un type scalaire genre double (ou CLLocationDegrees qui est équivalent), alors c'est les %@ qu'il faut remplacer par des %f...
  • zoczoc Membre
    juin 2009 modifié #16
    dans 1244114672:

    Sauf que faire [tt]lat = [SpotDetailsObj.lat retain];[/tt] dans ta 2e solution zoc n'est pas suffisant, car si on passe 2 fois dans la même méthode, la 2e fois lat n'est pas nil et tu oublies de le releaser...


    Exact, je m'en suis rendu compte pendant le trajet entre la maison et le bureau  :). C'est de toute façon un truc que je n'aurais jamais écrit si je devais le coder (préférant systématiquement ma 2eme solution).

    Je voulais aussi faire remarquer que ma dernière méthode, en plus de leaker dans certains cas, n'est absolument pas "KVO compliant", ce qui peut poser problème si on utiliser KVO...
  • allianallian Membre
    17:29 modifié #17
    Bon j'ai déjà  résolu un probleme puisque en effet dans ma BD lat et lon était des doubles alors qu'au début c'étaient des string. J'avais donc oublier de modifier la ligne sqlite3_column_text par sqlite3_column_double.

    Maintenant je récupère bien des NSString à  partir de double et je les assigne à  mes variables lat et lon de ma classe.
    Voici leur déclaration dans le .h
    @property(nonatomic, retain) NSString *lat;<br />@property(nonatomic, retain) NSString *lon;
    


    Je les release ensuite dans dealloc.
    Tout marche nikel sauf si je release aussi le SpotDetailsDB (ici en commentaire) :

    SpotDetailsDB *SpotDetailsObj = [[SpotDetailsDB alloc] init];<br />	[SpotDetailsObj getInitialDataToDisplay:[appDelegate getDBPath] andSpotId:spotID];<br /><br />	self.title = SpotDetailsObj.name;<br />	nameLabel.text = SpotDetailsObj.name;<br />	descLabel.text = SpotDetailsObj.description;<br />	tideLabel.text = SpotDetailsObj.bestTide;<br />	swellLabel.text = SpotDetailsObj.bestSwell;<br />	windLabel.text = SpotDetailsObj.bestWind;<br />	typeLabel.text = SpotDetailsObj.type;<br />	lat = SpotDetailsObj.lat;<br />	lon = SpotDetailsObj.lon;<br />	<br />	//[SpotDetailsObj release];<br />&nbsp; &nbsp; [super viewDidLoad];<br />
    


    Ceci me fait planter le lancement de cette méthode :

    -(void)showPlan:(id)sender {<br />	NSString *infoBulle = [nameLabel.text stringByReplacingOccurrencesOfString:@&quot; &quot; withString:@&quot;+&quot;];<br />	NSString* url = [NSString stringWithFormat:@&quot;http://maps.google.com/maps?q=%@,%@+(%@)&quot;,lat,lon,infoBulle];<br />	[[UIApplication sharedApplication] openURL:[NSURL URLWithString:url]];<br />}
    


    Donc voila je sais pas trop pourquoi.

    PS : c'est quoi KVO ?
  • allianallian Membre
    17:29 modifié #18
    Ouf problème résolu, du moins celui la, comme dit précédemment lat et lon était avec un retain donc je faisais un release dans dealloc.
    ça crashait toujours dans ma méthode avec le stringWithFormat, et maintenant ca ne crash plus depuis que j'ai rajouté un self.lat et self.lon devant...
    Je pense que cela vient du fait que dans mon objet SpotDetailDB il y avait aussi des attributs lat et lon et que du coup il pensait que c'était ceux la et donc voila pourquoi quand je faisais le release de ce dernier l'app crashait !!
    C'est très étrange mais bon... l'important est que maintenant cela fonctionne  :o :o :o :o :o :o



    Par contre j'ai un autre soucis encore révélé par Clang, c'est celui la :


    MyTag *monTag = [[MyTag alloc] init];<br />[2] Method returns an Objective-C object with a +1 retain count (owning reference).<br />138	&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; monTag.myName = [[tagsList objectAtIndex:i-1] objectForKey:@&quot;name&quot;];<br />139	&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //monTag.urlImage =[[tagsList objectAtIndex:i-1] objectForKey:@&quot;vignette&quot;];<br />140	&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; monTag.rootNavController = super.navigationController;<br />141	&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />142	&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; monTag.x = x;<br />143	&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; monTag.y = y;<br />144	&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />145	&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (Down == NO)<br />[3] Taking true branch.<br />[4] Object allocated on line 137 and stored into &#39;monTag&#39; is no longer referenced after this point and has a retain count of +1 (object leaked).<br />146	&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br />147	&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; x += 150;<br />148	&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Down = YES;<br />149	&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br />150	&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else<br />151	&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br />152	&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; y += 60;<br />153	&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; x -= 150;<br />154	&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Down = NO;<br />155	&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br />156	&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />157	&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [myScrollView insertSubview:monTag.view atIndex:0];<br />158	&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //[monTag release];
    


    Si je fais un release comme conseillé, mes vues ne s'affichens plus à  l'ecran !
    Une idée ?

    Merci encore
  • zoczoc Membre
    juin 2009 modifié #19
    dans 1244120183:
    Je pense que cela vient du fait que dans mon objet SpotDetailDB il y avait aussi des attributs lat et lon et que du coup il pensait que c'était ceux la


    Non. Un compilateur ne pense pas...

    En supposant qu'on ait :

    @property (nonatomic, retain) NSString *lon;

    Il y a une énorme différence entre

    lon = SpotDetailsObj.lon;

    et

    self.lon = SpotDetailsObj.lon;

    Les 2 vont modifier la même variable, MAIS:

    La premiere solution se contente d'affecter directement la valeur de SpotDetailsObj.lon à  la variable d'instance lon. Elle ne respecte donc PAS la clause retain de la property. Donc quand SpotDetailsObj est releasé, sa propriété lon est aussi releasée (par le dealloc de SpotDetailsDB), et par conséquent boom ça plante....

    La seconde solution va en fait appeler la méthode setLon générée automatiquement par le @synthetise lon. Cela a pour effet de respecter la clause retain déclarée dans la property. Donc un retain sera effectué automatiquement lors de l'assignement. C'est donc la seconde solution qu'il faut employer. Encore une fois, en ce qui me concerne, pour éviter toute confusion, j'utilise systématiquement le setter généré (setLon:) et pas la notation pointée.

    Pour terminer: KVO c'est un mécanisme qui permet à  un objet d'observer les propriétés d'un autre objet. Tant qu'on utilise les setters générés (ou la notation pointée, puisque c'est exactement la même chose), le nécessaire pour le fonctionnement de KVO est automatiquement appelé.

    Si on utilise pas les setters, ou si on code son propre setter à  la main, il faut rajouter le code suivant en gras pour que les objets qui observent la propriété soient notifiés:

    - (void)setLon:(NSString *)newLon
    {
        if (newLon != lon) {
            [self willChangeValueForKey:@lon];
            [lon release];
            lon = [newLon retain];
            [self didChangeValueForKey:@lon];
        }
    }

    Pour conclure: Vu les erreurs de gestion mémoire que tu fais et les confusions au niveau du fonctionnement  de propriétés, je te conseille vivement la (re)lecture de la documentation officielle d'Apple concernant la gestion mémoire et les spécificités du langage Objective C 2.0... Puis éventuellement les documents concernant KVC et KVO, qui sont 2 notions importantes, et qui deviennent carrément indispensables le jour où tu veux développer des applications pour Mac.
  • allianallian Membre
    17:29 modifié #20
    Merci beaucoup pour toutes ces explications cela m'a éclairé sur pas mal de points.  :) :)
    Du coup j'ai revu un peu mes 2 applis afin de vérifier si je ne faisais pas la meme erreur à  d'autres endroits. Merci.

    dans 1244127268:

    dans 1244120183:
    Je pense que cela vient du fait que dans mon objet SpotDetailDB il y avait aussi des attributs lat et lon et que du coup il pensait que c'était ceux la


    Non. Un compilateur ne pense pas...

    MDR 

    Je suis chiant mais tu n'aurais pas une idée à  propos de mon autre probleme ou de mon autre post Dealloc non appelé ??
    Désolé d'abuser...
  • zoczoc Membre
    17:29 modifié #21
    dans 1244120183:

    Par contre j'ai un autre soucis encore révélé par Clang, c'est celui la :
    ...
    Si je fais un release comme conseillé, mes vues ne s'affichens plus à  l'ecran !
    Une idée ?


    C'est simple:

    • Soit il n'y a pas de release, et effectivement, l'objet pointé par monTag ne sera jamais détruit, puisque en tant que propriétaire de l'objet, le créateur est seul responsable de sa destruction.
    • Soit il y a un release, mais alors il manque quelque part un autre objet (la vue ?) qui doit prendre possession de l'objet crée (par un retain) avant sa libération par son créateur. Parce que si ce n'est pas fait, l'objet sera détruit, et si la vue en a besoin pour s'afficher, ce qui semble être le cas, elle risque évidemment d'avoir du mal.
  • allianallian Membre
    17:29 modifié #22
    Je suis bien ton raisonnement qui est très clair le problème est que ma vue est une scrollVue crée dans IB et pour laquelle j'ai un outlet du coup à  part en créant ma propre classe je vois pas trop comment faire un retain sur l'objet myTag que j'y insère.
Connectez-vous ou Inscrivez-vous pour répondre.