Array/ObjectControllers: (strong ou weak) IBOutlets?
Bonsoir,
Une application qui tourne parfaitement sur mes machines de développement (10.9) se plante systématiquement sur 10.8 avec ce message de la console: Controller cannot be nil.
Je me demandais si cela pouvait provenir d'un objet explusé de la mémoire faute de place ou au mauvais moment, et si cela avait une chance de provenir d'un mauvais réglage.
Mes outlets sont tous weak. C'est ainsi que le Refactor les a déclarés lorsque j'ai converti mon projet en ARC.
Certains de ces outlets sont des contrôleurs, dont le document doit vérifier le contenu. A un moment, l'un de ces contrôleurs est passé en paramètre à une routine, c'est celle-ci qui semble poser problème.
Dès lors, ces contrôleurs (qui disparaissent avec le document) ne devraient-ils pas être déclarés comme strong durant la durée de vie du document?
Spécialistes de la mémoire, merci du coup de main.
Réponses
Il faut utiliser strong pour les Controllers.
C'est marqué clairement dans les release notes ARC:
Pyroh,
Merci pour le lien. Cette restriction est-elle toujours valable pour 10.8 (mon OS cible)?
Ok, j'ai passé mes outlets en strong dans le document. Je testerai demain. Entretemps, je vais faire la chasse à d'éventuels "retain" (strong) cycles...
J'ai déjà eu ce genre de problème sous 10.8 j'ai pas retenté le coup sous 10.9.
Maintenant je ne pense pas que cela pose un problème, un controller c'est pas non plus 200mo de RAM de bouffé... Si c'est déjà 200ko c'est déjà beau ^^
Mon application entière fait 633K (143K de code), mais elle en fait des choses pour si peu :P
Je ne pense pas que le système évacue le contrôleur pour sa taille, il a une gestion globale et si le retain d'un objet de 210 octets atteint zéro, hop, poubelle! Et l'objet en question peut être vital...
Mais je note que tu as eu des problèmes de ce type sous 10.8, c'est donc un indice assez fort que l'avertissement reste valable. En tout cas, j'ai vérifié, je n'ai pas de leaks.
Et pas étonnant que la recherche de zombies n'ai rien donné, puisque les weaks sont remis à NIL une fois purgés...
Ce n'était pas ça.
Je commence à m'échauffer un peu: l'application tourne sur un MacBook Air sous 10.8, mais continue à se planter sur les iMac dotés du même système (récents et équipés de 8Go de mémoire)...
J'ai généré des sous-classes de tous mes NSManagedObjects, avec des propriétés du bon type d'objet: pas de id qui traà®ne. Plus un seul setValue... forKey avec un risque de variable mal orthographiée (le plus drôle c'est que la taille de l'application a diminué et non augmenté).
J'ai farci mon code de NSLog. Ils m'indiquent que mes objets sont du type souhaité, pas un seul NIL, pas de leaks ni de zombies dans Instruments.
Et toujours ce "Controller cannot be nil" provoqué par les lignes:
Si je mets en commentaire les lignes qui concernent le menu, l'app tourne " mais elle n'est pas utilisable. En tout cas l'erreur est quelque part dans ces lignes.
C'est un problème de binding par code.
Qu'est-ce que j'ai bien pu négliger?
C'est intriguant comme soucis...
Ecco.
Personnellement quand j'ai des properties qui sont en fait des variables d'instance, je mets strong. Essaie déjà avec ça pour popUp et info.
Et est-ce qu'il est possible d'avoir le log d'erreur en entier ?
J'ai essayé weak, strong, et par défaut comme ici (je crois que c'est strong le défaut). Même résultat:
Un bug de ce type? J'ai tout vérifié...
http://www.cocoabuilder.com/archive/cocoa/122136-strange-nswindowcontroller-memory-leak.html
Essaie de binder sur self au lieu de self.popUpAprès je suis à court d'idéeC'est dans l'init les autres objets ne sont pas encore tous créés ! Faut le mettre dans awakeFromNib normalement
J'ai posté ça vite fait avant de me coucher hier, en fait il n'y a que le NSPopupButton qui contient autre chose que Nil. A l'init rien n'assure que les outlets sont déjà instanciés par le nib (généralement ils ne le sont pas).
AwakeFromNib est fait pour ça
J'ai trouvé l'un des bugs (because "there is always another bug"...)
La doc est "claire", enfin, aussi claire que d'habitude:
Maintenant, que faut-il entendre par observableController? Les exemples donnés, ainsi que les objets proposés dans la liste des observables dans le cas de IB, sont des objets de type Controller (Array-, Object-, Tree-, View-).
Mon troisième paramètre est un NSManagedObject dérivé. Il ne fait donc pas l'affaire. Dès lors, j'avais (me semble-t-il) deux choix:
a- créer un Controller pour surveiller mon objet.
b- ne pas lier le menu par binding.
J'ai fini par utiliser ceci :
Comme le disait Céroce dans un autre sujet: "Ce qui complique tout, ce sont les bindings". Mais il se trouve que j'adore le procédé, même si là , il vient de me faire passer de mauvais moments...
Puisque l'erreur ne se situait pas dans une mémoire purgée au mauvais moment, mes questions deviennent:
1. Si bind attend comme troisième paramètre un NSController, pourquoi le compilateur accepte-t-il un NSManagedObject ?
2. Surtout, étant donné qu'il s'agit d'un bug, et d'un vrai, comment expliquer le comportement conciliant de mon environnement de développement, qui n'a jamais bugué? Ma volonté suffirait-elle à influencer la machine?
Bref, c'est une solution qui m'amène plus de questions que de réponses. Mais peut-être quelqu'un sait-il?
Toi t'as pas lu ce que j'ai posté plus haut ^^
Il ne faut pas mettre ça dans l'init !
Toi non plus
C'est un initWithFrame, ce qui laisse supposer une initialisation par code, pas un chargement depuis un nib. En fait, cette routine est appelée d'innombrables cycles après le lancement de l'application, lorsque l'utilisateur, de son rythme pesant, décide de rajouter un objet particulier à une liste. Tous les contrôleurs sont instanciés, leur contenu est chargé, les tableviews remplies.
Tu n'aurais pas une explication au fonctionnement "miraculeux" de mon bug ?
Binder sur self ou compiler avec le SDK 10.8
Après je vois pas
J'ai fini par télécharger Xcode sur une machine 10.8 et, encore une fois, constaté un comportement différent...
Il y a quelque temps, j'avais lu qu'un développeur Windows était bien mal loti, puisqu'il devait tester son programme sur des tas de systèmes et des tas de machines différentes, alors que le développeur Mac ne connaissait pas ce genre d'inconvénient.
Dommage que j'aie perdu la référence. J'aurais volontiers ajouté un petit bémol à cette déclaration quelque peu optimiste...