respondsToSelector: sent to deallocated instance : Les zombies suffisent pas !

Bonjour,

Je fait face à  un problème assez curieux.
J'ai reproduit sur Mac OS X un clone de la classe UINavigationController. Son comportement est similaire à  ce que l'on voit sur iPhone.
Les ViewControllers que je "push" sur mon navigation controller sont des NSViewController sousclassés contenant un navigationItem, toujours dans l'analogie avec le fonctionnement sous iPhone OS.

J'utilise ce système pour reproduire une navigation à  la Front Row entre des viewControllers présentant des TableViews.
Je l'utilise depuis des mois sans soucis. Mais voilà , je rencontre un soucis inexplicable ! Tous tes mes sous-classe de PMViewController existantes peuvent être poussés sans soucis, mais si j'en crée une nouvelle et que je la "push", si je release mon navigation controller, j'ai un "respondsToSelector" envoyé à  ce PMViewController alors qu'il a été releasé suite au release du navigationController. C'est d'autant plus curieux que je ne garde aucun pointeur dessus dans aucune de mes classes !

Ce que je voudrais, c'est savoir quelle instance de quelle classe envoi ce "respondsToSelector" à  mon viewController releasé ? je ne le fait nulle part dans mes propres classes, c'est donc d'autant plus difficile à  débugger.

Réponses

  • CéroceCéroce Membre, Modérateur
    février 2010 modifié #2
    Le zombie te dit pas quel objet a envoyé le message ? Il me semble qu'il donne son adresse.
    Dans la console tu dois pouvoir taper

    po 0x54560d
  • AliGatorAliGator Membre, Modérateur
    21:37 modifié #3
    Sinon met un breakpoint sur méthode (par opposition à  un breakpoint sur une ligne donnée d'un fichier .m)
    Tu mets un breakpoint sur "-respondsToSelector:" et ce breakpoint devrait mettre en pause le programme à  chaque fois que cette méthode est appellée, quel que soit l'endroit d'où c'est appelé.
  • Nebuchad34Nebuchad34 Membre
    21:37 modifié #4
    Le débugger me sort ça

    2010-02-10 12:23:18.874 Poker Manager[8002:a0f] *** -[PMITunesMenuController respondsToSelector:]: message sent to deallocated instance 0xc8200b0

    et si je fais :

    (gdb) po 0xc8200b0

    et bien il me reprint ça :

    2010-02-10 12:23:30.751 Poker Manager[8002:a0f] *** -[PMITunesMenuController respondsToSelector:]: message sent to deallocated instance 0xc8200b0

    Ali, comment je fait pour mettre un breakpoint sur methode ?
  • AliGatorAliGator Membre, Modérateur
    février 2010 modifié #5
    Tu vas dans la fenêtre des Breakpoints (Je sais plus dans quel menu c'est pour l'afficher, donc tu cliques sur le menu "Help", et dans la zone de recherche spotlight qui se trouve dans ce menu Help tu tapes "breakpoint", tu verras bien où il se trouve :P), et tu cliques pour rajouter une entrée, en tapant "-respondsToSelector:", ou mieux "-[PMITunesMenuController respondsToSelector:]" ou un truc comme ça.

    (Et puis si c'est plus ça la syntaxe, au pire ça doit bien être marqué dans l'aide ou via une recherche "breakpoints site:developper.apple.com" via Google :P)
  • AliGatorAliGator Membre, Modérateur
    21:37 modifié #6
  • AliGatorAliGator Membre, Modérateur
    21:37 modifié #7
    Sinon ton problème peut être dû à  un écrasement mémoire aussi éventuellement. Genre ça appelle respondsToSelector mais sur une variable qui n'est pas du tout sensé être de type PMITunesMenuController, sauf que si c'est une variable que tu as releasée et que tu continue à  utiliser cette variable après ça... bah entre temps la zone mémoire vers laquelle pointe ta variable a pu être remplie par autre chose qui n'a rien à  voir... du coup tu appelles la méthode respondsToSelector sur un objet qui est un peu n'importe quoi (mais n'est pas ce qui est attendu) et paf.

    Bien évidemment, la première chose à  faire est une analyse statique de ton code ("Build & Analyze" dans le menu "Build", ou Pomme-Maj-A) pour essayer de détecter les erreurs de gestion mémoire que tu aurais laissé passer (l'analyse statique ne trouve pas forcément toutes les fuites mémoires, mais celles qu'elle trouve sont en général réelles, donc faut de toute façon au moins les corriger avant d'aller plus loin !)
  • Nebuchad34Nebuchad34 Membre
    21:37 modifié #8
    Le problème ne semble pas être au niveau de ma gestion de la mémoire. Rien pour l'analyse analytique.
    Mettre un breakpoint sur respondsToSelector c'est ingérable. Il arrête sans arrêt.
  • AliGatorAliGator Membre, Modérateur
    21:37 modifié #9
    dans 1265824809:
    ... l'analyse analytique.
    :D Pas mal celle-là   :o
    dans 1265824809:
    Mettre un breakpoint sur respondsToSelector c'est ingérable. Il arrête sans arrêt.
    Ben oui mais et alors ? personnalise un peu, ne demande qu'à  s'arrêter qu'au bout d'un certain nombre de hits seulement (avec un peu de dichotomie tu devrais trouver un ordre de grandeur du nombre de hits du breakpoint au bout duquel il plante), ou tu mets des conditions sur tes breakpoints...

    Sinon, puisque tu sembles dire que ça n'arrive qu'aux instances que tu crées par le code (via alloc/init dans ton code j'imagine), tu peux récupérer l'adresse mémoire de l'instance créée, et ne mettre ton breakpoint que sur cette instance-là  (voire un inspecteur (watch variable) pour être informé quand la valeur à  cette adresse mémoire change...

    Et puis sinon puisque tu n'as ce cas que pour ces instances particulières là  encore, tu peux ne mettre tes breakpoints (sur -respondsToSelector: comme sur tes adresses mémoires, etc) qu'après avoir envoyé le release.

    Tu es sûr que tu n'as pas une méthode qui te retourne un objet autoreleasé... et que tu envoies un release supplémentaire sur cet objet ?

    Quelle est la tête de la callstack quand ça plante à  cet endroit ?
  • Nebuchad34Nebuchad34 Membre
    21:37 modifié #10
    ça ressemble à  ça.

    #0 0x96e8bab7 in ___forwarding___
    #1 0x96e8b982 in __forwarding_prep_0___
    #2 0x97cc04e7 in +[NSTextInputContext currentInputContext]
    #3 0x97cc00ab in -[NSApplication updateWindows]
    #4 0x97cbffd2 in _handleWindowsNeedUpdateNote
    #5 0x96e91892 in __CFRunLoopDoObservers
    #6 0x96e4e18d in __CFRunLoopRun
    #7 0x96e4d864 in CFRunLoopRunSpecific
    #8 0x96e4d691 in CFRunLoopRunInMode
    #9 0x90a7bf0c in RunCurrentEventLoopInMode
    #10 0x90a7bbff in ReceiveNextEventCommon
    #11 0x90a7bb48 in BlockUntilNextEventMatchingListInMode
    #12 0x97cbeac5 in _DPSNextEvent
    #13 0x97cbe306 in -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:]
    #14 0x97c8049f in -[NSApplication run]
    #15 0x97c78535 in NSApplicationMain
    #16 0x00008fe7 in main at main.m:13


    Et non, pas d'objet autoreleasé. C'est vraiment très bizarre.
    Je pousse plein de vues controlleur qui sont des sous classes de mon PMViewController et j'ai pas de pb.
    Si j'en fait une nouvelle sur le même modèle que les précédentes, ça merdouille !

    Ce qui ets bizarre c'Est que ça ne plante pas quand je pop le view controller, mais quand je release directement mon navigation controller après l'avoir retiré de la vue de ma fenêtre.
    Si je pop mon view controlelr pour revenir à  ma first view et que je vire mon navigation controller là  ça ne plante plus !

  • Nebuchad34Nebuchad34 Membre
    21:37 modifié #11
    Pour bien expliquer le problème, une vidéo vaut mieux qu'un long discours :

    http://www.cocoatreeapplications.com/_videos/bugRespondsToSelector.m4v

    Vous allez comprendre pourquoi je vous dit que c'est très bizarre  >:) .

    Cela fait deux jours que je bute là  dessus, j'en ai maaaaaaaarrre  :'(
  • AliGatorAliGator Membre, Modérateur
    21:37 modifié #12
    Met le breakpoint sur respondsToSelector juste avant de cliquer sur ton bouton qui fait planter.
    Et affiche la callstack (je suis pas habitué à  ce layout de Xcode, je préfère le "All-In-One" où, quand tu débug, tu as tout sous les yeux, callstack, variables, console, breakpoints, ... là  dans ta vidéo tu as juste la console c'est pas très parlant pour déboguer)
Connectez-vous ou Inscrivez-vous pour répondre.