Crash sur NSUserDefaults
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
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 ?
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:@"conditions"];<br /> NSLog([standardUserDefaults objectForKey:@"mail"]);<br /> NSLog([standardUserDefaults objectForKey:@"login"]);<br /> <br /> if ([[standardUserDefaults objectForKey:@"mail"] isEqualToString:@""] & [[standardUserDefaults objectForKey:@"login"] isEqualToString:@""] | 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 ?
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
De plus il est bon de "parenthèser" tes expressions, pour leur mettre des priorités, quand tu mélanges les && et les ||...
Mieux vaut utiliser NSLog(@%@",...)
Voila ce que me sort le debugger :
Sinon vous avez pas une idée pour mon tableau qui persiste en mémoire ?
Je fais cela dans ma classe MyBleeker:
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
Normalement le BleekerViewController est un nouveau à chaque fois non ?
Pourquoi mon tableau reste t il 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...
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 :
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 :
Tout ce que je vois, ce sont des Warning sans réelle importance pour la stabilité de l'application.
Symptôme typique d'un écrasement mémoire ou de tentative d'accès à un objet qui a été détruit trop tôt...
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...
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.
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
- 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.
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 :
J'effectue bien mes releases là ?
Et ici :
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
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.
J'attribue toutes mes valeurs et dans une autre méthode je fais ceci :
Et les deux nsstring lat et lon n'ont plus la bonne valeure du coup ça plante...
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 ?
ou (je déteste la notation "." introduite avec Objective-C 2.0 et personnellement j'écris toujours "à l'ancienne):
tu devrais pouvoir faire un release sur SpotDetailsObj sans avoir de problèmes par la suite.
L'autre solution c'est d'écrire :
(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.
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...
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...
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
Je les release ensuite dans dealloc.
Tout marche nikel sauf si je release aussi le SpotDetailsDB (ici en commentaire) :
Ceci me fait planter le lancement de cette méthode :
Donc voila je sais pas trop pourquoi.
PS : c'est quoi KVO ?
ç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
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 ?
Merci encore
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.
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.
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...
C'est simple: