Problème avec un singleton
Flo
Membre
Bonjour à tous,
J'ai créer un singleton selon la méthode fournie par la doc d'Apple :
http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaFundamentals/CocoaObjects/CocoaObjects.html#//apple_ref/doc/uid/TP40002974-CH4-SW32
Je créer également un petit cube bleu de la classe de mon singleton dans un fichier xib. Dans ce xib j'ai un bouton qui pointe sur une IBAction de mon singleton.
Dans ce même xib il y a également une instance de mon AppController.
Le problème est le suivant, si je fait un truc du style :
Si on essaye ensuite d'appuyer sur le bouton relié à l'IBAction du singleton, ça ne fait rien
Si je commente la ligne [MonManager sharedManager], tout remarche.
Je suppose que la méthode init de l'AppController doit être appelée avant et donc instancier en premier le singleton. Or lorsque le xib créer le cube bleu en appelant la méthode init, ça doit lui renvoyer nil...
Une petite idée sur la manière d'arranger ça ?
J'ai créer un singleton selon la méthode fournie par la doc d'Apple :
http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaFundamentals/CocoaObjects/CocoaObjects.html#//apple_ref/doc/uid/TP40002974-CH4-SW32
Je créer également un petit cube bleu de la classe de mon singleton dans un fichier xib. Dans ce xib j'ai un bouton qui pointe sur une IBAction de mon singleton.
Dans ce même xib il y a également une instance de mon AppController.
Le problème est le suivant, si je fait un truc du style :
<br /><br />// Dans AppController également instancié par le fichier xib<br /><br />- (id) init<br />{<br /> self = [super init];<br /><br /> if (self) [MonManager sharedManager];<br /><br /> return self;<br />}<br /><br />
Si on essaye ensuite d'appuyer sur le bouton relié à l'IBAction du singleton, ça ne fait rien
Si je commente la ligne [MonManager sharedManager], tout remarche.
Je suppose que la méthode init de l'AppController doit être appelée avant et donc instancier en premier le singleton. Or lorsque le xib créer le cube bleu en appelant la méthode init, ça doit lui renvoyer nil...
Une petite idée sur la manière d'arranger ça ?
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Le problème c'est que ça initialise le manager avant que le programme ne le créer avec la méthode init dans le fichier .xib. Et du coup ça fait foirer toutes les laisons que j'ai faites dans IB entre MonManager et le reste de l'interface...
C'est tout de même dommage qu'on ne puisse pas toucher au singleton tant que le xib ne l'ai pas lui-même instancié >:(
Je ne vois pas trop en quoi le fait que le XIB crée ton singleton avant ou après change les choses... à condition que tu fasses en sorte que la méthode initWithCoder de ton singleton, qui sera appelée typiquement par le XIB lors du désarchivage, fasse la mm chose que sharedInstance, à savoir crée l'instance si elle n'existe pas déjà , sinon relâche la mémoire éventuellement allouée pour self et retourne la sharedInstance déjà existante de ton singleton
La dernière contribution me semble être la meilleure façon d'avoir un singleton "dans un NIB", et qui soit également utilisable avant d'avoir chargé le NIB...
Ben dans le code fournis par Apple(sans init) apparemment ça change tout si on ne surcharge pas init (ce que je n'avais pas fait pensant que ça suffirait). Merci pour l'info
Merci pour le lien , je pense que c'est ce qu'il me faut, je vais tester.
Non dans le cas d'un NSObject présent dans le nib, c'est init qui est appelé pas initWithCoder:. dixit NSNib
Je ne comprends plus rien... il y aurait-il une part d'aléatoire dans la manière d'instancier les éléments d'un fichier xib ?
Ce qui est marrant c'est que quand j'ai rajouté la méthode init ça a marché. Je relance XCode un peu plus tard et la ça craque sans qu'il n'y ai eu aucunes modifs de ma part...
Quand ça ne marche pas, il suffit que je commente le init de l'AppDelegate pour que ça remarche, et après si je décommente et bien ça marche ! (enfin pas tout le temps)
[move] ;D ;D ;D ;D ;D ;D [/move]
Ya de quoi devenir dingue...
Le alloc fait passer par allocWithZone, donc crée le singleton
init se contente de le renvoyer ..
Je vais essayer d'éteindre XCode, et d'allr faire un tour pour voir si y aurait quelque chose ... ;D
Voilà je suis revenu. Cela fonctionne. Je joins le code du mini-projet pour ceux qui voudrait faire des essais de confirmation.
Quand on appelle la méthode sharedInstance (si on suppose qu'on met pas le singleton dans le nib, quoi mais qu'on l'appelle la première fois par code), ça fait un alloc => allowWithZone, puis un init... qui renvoie sharedInstance sans appeller le init de NSObject ? pas super propre, non ?
Et si on fait le alloc/init nous-même (au lieu d'appeler sharedInstance), ou si on laisse le désarchivage du XIB faire ce alloc/init, bah ça fait le allocWithZone suivi du init, donc tout pareil, du coup ça c'est OK je pense.
Mais ne pas appeler le [super init] me choque un peu...
On peut le faire pour faire propre, mais le init de NSObject ne fait rien.
doc sur -(id)init
"An object isn't ready to be used until it has been initialized. The init method defined in the NSObject class does no initialization; it simply returns self."
[EDIT]
Voila ce qu'affiche le log quand ça ne marche pas :
2009-06-05 18:29:06.631 Untitled[618:10b] allocing with zone
2009-06-05 18:29:06.634 Untitled[618:10b] initializing
2009-06-05 18:29:06.635 Untitled[618:10b] allocing with zone
2009-06-05 18:29:06.641 Untitled[618:10b] allocing with zone
Quand ça marche, il y a seulement :
2009-06-05 18:29:06.631 Untitled[618:10b] allocing with zone
2009-06-05 18:29:06.634 Untitled[618:10b] initializing
Essayez plusieurs fois jusqu'à avoir la situation d'erreur... souvent chez moi ça survient quand on laisse XCode allumé un petit moment sans rien faire et qu'on relance la compile (pomme + R)
Le fait de poser une target/action se fait normalement après les initialisations de tous les éléments du xib, donc je ne vois pas de problème de synchronisation.
Bizarre
Chez moi après certain build ça le fait, et l'appuie sur le bouton ne produit aucun message dans la console...
En ajoutant un deuxième MySingleton dans le xib, j' ai le message
Puis en supprimant le 2ème, cela ne marche plus.
Je peux encore supprimer le premier et là j'ai un simple
C'est comme si quelque part quelque chose était mémorisé ...
Les initialisations d'un objet présent dans le nib se font en général dans awakeFromNib.
Oui, c'est quand même bizarre que des fois ça marche et des fois pas sans ne rien toucher au projet...
Oui c'est certain que le problème vient de là , ce que je ne comprends pas c'est pourquoi ça ne fonctionne pas malgré toutes les précautions qui sont prises...
Bon de toute façon ce n'est pas gênant de déplacer mon code dans awakeFromNib (moins que dans appDidFinishLaunching:). C'est même plus philosophie cocoa.
Merci d'avoir donné de ton temps et de ta patience
Je n'ai pas voulu créer un nouveau sujet pour une si petite question :)beta:
J'ai pas mal de singletons dans mon projet qui font des traitements plutôt similaires, je me suis donc naturellement demandé s'il était possible de les faire hériter d'une même classe plus générale étant elle-même un singleton ?
Je prés-sens fortement que la réponse est non mais qui ne tente rien n'a rien
A essayer, en premier lieu avec dans chaque fichier .m des classes-fille une redéfinition de la variable statique sharedInstance.
Si tu fais des essais, tiens nous au courant, c'est rigolo
Perdu !
La réponse est oui et c'est même l'avantage principal du singleton !
Sinon autant utiliser des méthodes et des variables statiques, ça marche aussi bien
Oui en effet !
J'ai fait un premier petit essai(en partant du projet de Philippe) et ça marche pas trop mal, je vous le met en pièce jointe.
Si vous avez des remarques, des astuces ou des améliorations, je suis preneur !
Quand on créer plusieurs instances de MySingleton héritant de MySuperSingleton, ça crash de partout. Je pense qu'il faut redéfinir toutes les méthodes dans MySingleton, et de toute manière il y aura un conflit pour la méthode allocWithZone: ...
ça va être plus dur que ce que je pensais
Mais c'est vrai que ce sont des questions qui au final éclaircissent beaucoup de choses.