Crash avec NSLocalizedString
Bonjour,
J'ai attaqué la localisation d'iPocket Draw et j'ai un crash bizarre avec NSLocalizedString lors de l'affichage d'une UIActionSheet.
Sans les NSLocalizedString, pas de problème, mais avec ça passe une fois ou deux et ensuite crash sur "objc_msgSend".
A d'autres endroits j'ai également des NSLocalizedString qui fonctionnent sans problème.
Ai-je loupé quelque chose ?
Merci
Eric
J'ai attaqué la localisation d'iPocket Draw et j'ai un crash bizarre avec NSLocalizedString lors de l'affichage d'une UIActionSheet.
Sans les NSLocalizedString, pas de problème, mais avec ça passe une fois ou deux et ensuite crash sur "objc_msgSend".
A d'autres endroits j'ai également des NSLocalizedString qui fonctionnent sans problème.
Ai-je loupé quelque chose ?
Merci
Eric
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Ce n'est pas un manque de retain ?
Un NSLog sans @ : comme NSLog("identifier"," ");
Un fichier de localisation absent, tu dois avoir quelque chose comme l'image
ce code :
crash au 2ème ou 3ème appel.
Si je n'utilise pas le "NSString* sheetTitle" donc en mettant directement le NSLocalizedString(@Sendbymailas, @"") à sa place à la ligne initWithTitle:
je n'ai pas de crash.
Ce qui est bizarre (je crois) c'est que je n'ai pas le crash si dans le code ci-dessus je supprime la ligne "[sheetTitle release];"
Enfin le principal est d'avoir une solution qui fonctionne.
Merci
Eric
Dans l'esprit de ton code, il aurait fallu mettre
NSString* sheetTitle = NSLocalizedString(@Sendbymailas, @"");
sans release
ou de manière plus compliquée :
NSString* sheetTitle =[ [NSString alloc] initWithString:NSLocalizedString(@Sendbymailas, @"")];
avec un release.
Ca m'énerve un peu toutes ces complications de release, retain, alloc et autres joyeusetés...
Pourquoi quand je fais directement NSString* sheetTitle = @xxx;
et avec le release, cela ne crash pas ?
Bonne nuit.
Eric
1) Lorsque tu utilises une constante, genre @xxx, c'est un cas particulier puisque c'est une constante, inclus dans les données du code compilé, en dur. En fait sous le capot ce type de NSString a un retainCount infini, tout comme un singleton d'ailleurs. On ne peut pas "releaser" une constante
2) Lorsque tu utilises NSLocalizedString(@xx), qui n'est qu'une macro qui fait appel à la méthode [tt][[NSBundle mainBundle] localizedStringForKey:@xx value:@"" table:nil][/tt] (c'est dit dans la doc, mais sinon un simple pomme+double-clic sur le mot "NSLocalizedString" dans ton code va te mener au #define correspondant sinon).
Or cette méthode va charger dynamiquement les chaà®nes depuis le bon fichier ".strings", selon le langage adéquat (et dans la table adéquat si elle est spécifiée)... donc sous le capot, y'a lecture du fichier texte, sans doute une mise en cache de la NSString j'imagine je sais pas trop comment...
Mais tout ce qu'on sait c'est que vu les conventions de nommage Apple, tu n'as pas à gérer la mémoire de la chaà®ne retournée par cette macro/cet appel. Très certainement est-elle en tout cas autoreleased.
Couclusion la question n'est pas tant pourquoi ça crash dans un cas et pas dans l'autre, même si, si tu veux tout savoir je viens de te donner la réponse (retainCount infini dans un cas car constante, autoreleased dans l'autre cas). La question c'est plutôt de savoir pourquoi tu mettrais un release ici, alors que tu n'as ni alloc ni copy ni retain correspondant donc pas besoin de release pour le "balancer"...
La règle est simple, ne faire un release que qd tu as toi mm fait un alloc ou un copy ou un retain... dans les autres cas, tu n'as pas à faire de release, c'est pas compliqué, faut pas se poser des questions plus loin ^^
Je pencherais plutôt pour une mise en cache, donc pas autoreleased, mais plutôt dans une zone mémoire où le release n'est pas autorisé.
Pour moi il est mis en cache qqpart dans le mécanisme interne de NSBundle je sais pas trop comment (et à vrai dire on s'en fout ^^ tout ce qu'on sait c'est qu'on a pas à gérer sa mémoire et ça devrait nous suffire :P), mais ça n'empêche pas, pourquoi pas, de se dire qu'il est autoreleased :
- soit parce qu'il est effectivement autoreleased (j'ai vu par exemple des accesseurs qui retournent [tt][[mavaleur retain] autorelease][/tt] au lieu de juste [tt]mavaleur[/tt], ça pourrait être dans ce cas)
- soit parce qu'en fait ok c'est pas réellement autoreleased, mais on peut considérer ça comme tel de l'extérieur, à savoir appliquer la règle : "d'abord c'est pas nous qu'on a créé l'objet donc c'est pas nous qu'on a à le releaser d'abord nan mais".
En effet on peut imaginer que qui dit "mise en cache" dis "une fois la chaà®ne chargée en mémoire à priori elle a des chances de restée chargée pdt toute la vie de l'appli... mais bon à la limite si on a besoin de mémoire car on est un peu court on peut la décharger, et la recharger alors du fichier quand on en aura re-besoin"... et là ça peut justifier un retain+autorelease au lieu de retourner la valeur direct.
Mais bon après je suis d'accord avec toi, c'est pas dit que ce soit autorelease en effet. Mais toujours est-il que bon... en fait en réalité pour l'utiliser, on s'en fiche, c'est pas nous qui faisons de alloc/copy/retain donc on a pas à se soucier de la gestion mémoire, comme quand ce sont des variables autorelease.
Alors pourquoi avais-je le release ?
Car le code provient d'un exemple avec la NSString initialisée avec alloc...initwithformat...
J'ai ce code ailleurs mais pour un second cas je l'ai modifié avec une constante d'abord puis avec NSLocalizedString mais en laissant le release.
Maintant je dois vérifier tout mon code.
On prend de bonnes habitudes avec REALbasic...
Merci
Eric
Conclusion de Tristan Bernard : "Il ne faut avoir confiance qu'en soi-même, et encore, pas beaucoup"
Il me semble qu'on peut faire autant de "retain", "release" qu'on veut sur un objet constant, son "retainCount" ne change point.
- Ca crash pas quand il utilise une constante, normal car retainCount virtuellement infini et retain/release sont alors des no-op...
- Ca crash qd il utilise NSLocalizedString, qui charge la chaà®ne dynamiquement et dans ce cas, qu'elle soit mise en cache qqpart ou autoreleased ou quoi, dans tous les cas c'est pas une constante.
Donc tout est normal.
Cependant il me semble que c'est l'application qui charge le fichier dans un dictionnaire au lancement, et pas NSLocalizedString qui va le lire dynamiquement (ce qui revient au même pour le release, certes...)
Et faut faire gaffe parfois avec ce qui semble être dynamique :P
Je vous laisse deviner ce que ça renvoie
Je suis content que mon erreur vous permette de philosopher ainsi...
Bon week-end.
Eric
(Voilà pourquoi c'est pas tjs bon de faire des tests et suppositions et d'en tirer des conclusions sur une classe comme NSString qui est un peu particulière, entre class cluster, optimisation, utilisation de constantes via @..., c'est une des classes les plus spécifiques en interne je pense, donc bon, méfiance quant aux conclusions dessus :P)
De quoi faire une thèse