Une erreur de selector bien étrange

GreensourceGreensource Membre
05:29 modifié dans API AppKit #1
Coucou.
J'ai une erreur bizarre pendant l'execution. C'est une Exception du à  un objet qui ne peut répondre à  un selecteur:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSCFType isDead]: unrecognized selector sent to instance 0x5513f0'

Sauf que je suis sur de ne jamais envoyer le message "isDead" à  un objet de type NSCFType, je ne sais même pas ce que c'est. D'autant que parfois j'ai la même erreur mais sur un UIColor???
Vous avez une idée de ce j'ai pu faire pour provoquer ça?

Réponses

  • AliGatorAliGator Membre, Modérateur
    05:29 modifié #2
    Non pas idée, mais une méthode simple pour résoudre ce genre de problème, c'est de rajouter une catégorie à  NSObject permettant de répondre à  ce message isDead, et de mettre un point d'arrêt dedans :
    @interface NSObject(Debug)<br />-(BOOL)isDead;<br />@end<br />@implementation NSObject(Debug)<br />-(BOOL)isDead {<br />&nbsp; NSLog(@&quot;oops&quot;); // mettre un point d&#39;arrêt (Breakpoint) sur cette ligne<br />}<br />@end
    
    A mettre par exemple dans le main.m

    Une fois que tu as mis ce code et le point d'arrêt sur la ligne indiquée, tu lances ton programme en mode Debug (Pomme-Y), et il devrait s'arrêter sur le point d'arrêt quand il essaye d'envoyer le message "isDead". Et là  dans le débogueur tu pourras alors avoir la "callstack", c'est à  dire la pile des appels de méthodes... tu pourras alors voir quelle méthode a appelé cette méthode isDead, et quelle méthode a appelé cette méthode, et remonter jusqu'à  la ligne de ton code qui a déclenché tous ces appels en série... restera plus qu'à  comprendre pourquoi cette ligne de ton code déconne et génère cet appel qui fait tout planter.



    Ceci dit vu le problème, m'est avis que tu gardes quelque part dans une variable un objet qui a été releasé entre temps. Du coup ta variable qui pointait avant sur ton objet pointe maintenant sur du n'importe quoi, du coup quand tu envoies un message à  cette variable ça part en cou... en vrille.
  • CéroceCéroce Membre, Modérateur
    05:29 modifié #3
    Pour régler les problèmes de retain/release des objets, tu peux utiliser NSZombie, un outil de débogage qui conserve les objets en mémoire même une fois relâchés.

    Plus d'infos ici.
  • GreensourceGreensource Membre
    avril 2009 modifié #4
    J'ai pas énormément de temps là , mais déjà  merci d'avoir répondu.

    Je me doutais que c'était une histoire d'Objet releasé trop tôt.
    J'ai essayer NSZombi, j'ai fait NSZombiEnabled=YES dans le terminal mais ça change rien. Je lirais plus attentivement la doc.

    Je vois tout ça et je vous redit, merci.

    [edit] Bon en fait j'ai regarder, ça doit-être ça puisque maintenant j'ai le message:
    Variable object not found

    Je vais continuer mes recherches.

    En tout cas merci, vraiment pas mal vos techniques
  • CéroceCéroce Membre, Modérateur
    avril 2009 modifié #5
    NSZombieEnabled est une variable d'environnement passée à  ton appli à  l'exécution.
    Pour fixer une variable d'environnement:
    - Dans l'onglet Targets, sélectionne l'exécutable
    - Menu File > Get Info > Onglet Arguments

    En bas, tu as la liste des variables d'environnement.
    - Crée la variable NSZombieEnabled, mets sa valeur à  YES.
    - Evidemment, coche-là .

    Fais juste gaffe, si NSZombie est activé, les objets restent en mémoire, pense donc à  décocher la case dès que tu n'en as plus besoin.
  • schlumschlum Membre
    05:29 modifié #6
    Pas besoin d'ajouter du code pour mettre un point d'arrêt  ;)
    Suffit d'ajouter à  la main le point d'arrêt "-[NSCFType isDead]"...
  • AliGatorAliGator Membre, Modérateur
    05:29 modifié #7
    Oui sauf que dans son cas, c'est pas toujours sur un NSCFType que ça semble planter ;)
  • schlumschlum Membre
    05:29 modifié #8
    Moi je sens que c'est un truc du Garbage Collector...
  • GreensourceGreensource Membre
    05:29 modifié #9
    J'ai pas encore eu le temps de revoir mon code mais je suis sous iPhone OS sans garbage collector. Mais je me connais j'ai du faire le con avec la libération des objets.  :)
  • schlumschlum Membre
    05:29 modifié #10
    C'est bizarre parce qu'il n'y a pas une seule mention à  "isDead" dans la toute la doc Apple (developer.apple.com)...
    ça fait vraiment message interne de GC qui cherche à  savoir si un objet n'a plus aucune référence.
  • GreensourceGreensource Membre
    05:29 modifié #11
    :) Nan mais c'est normal! J'ai dû mal m'exprimer, isDead est une méthode à  moi que j'envoies à  des Cases pour savoir si elles doivent être dessiner ou pas ^^
    Et du coup j'ai bien ce message envoyé à  une case libéré (d'être une case libéré, tu sais c'est pas si facile.Ne la laisse pas tombé, elle est si fragile... humhum dsl :P)
  • schlumschlum Membre
    05:29 modifié #12
    Ah ben t'aurais dû le dire avant ! C'est une info importante quand même  ???
    Du coup c'est probablement un problème de mémoire... Un objet libéré, sa structure objet a été remplacée par un objet NSCF alloué à  la même place mémoire... et paf.
  • GreensourceGreensource Membre
    05:29 modifié #13
    dans 1239656996:

    Ah ben t'aurais dû le dire avant ! C'est une info importante quand même  ???
    Du coup c'est probablement un problème de mémoire... Un objet libéré, sa structure objet a été remplacée par un objet NSCF alloué à  la même place mémoire... et paf.
    Bas ouais je pensais l'avoir fait  ::) merci
  • schlumschlum Membre
    05:29 modifié #14
    En fait, j'ai pris le " je ne sais même pas ce que c'est " pour le "isDead"...

    Tu as passé ton truc à  la moulinette CLANG ?
  • GreensourceGreensource Membre
    05:29 modifié #15
    Oui, Clang me dit que tout est nickel  :)
  • schlumschlum Membre
    05:29 modifié #16
    Clang doit se fourrer le doigt dans l'oe“il...
  • GreensourceGreensource Membre
    05:29 modifié #17
    Je pense qu'il ne voit pas que la libération de mon objet peut-être problématique ailleurs.
  • GreensourceGreensource Membre
    avril 2009 modifié #18
    C'est bon j'ai trouvé, mais dû coup je ne comprends pas très bien mon erreur. Cela viens d'un setter:
    <br />- (void)setTargetCase:(GWCase*)theCase<br />{<br />	if(targetCase!=theCase){<br />		[targetCase release];<br />		targetCase = theCase;<br />	}<br />	targetCase.highLight = YES;<br />}
    

    Ah bas si je crois que je comprends ma bêtise, j'ai mi l'affectation dans le if! C'est ça non?

    Sinon j'appel le setter comme ceci:
    board.targetCase = [[board caseAtPoint:thePoint] retain];
    

    C'est ok, ça? Faut bien un retain n'est-ce pas?


    [edit] J'ai une petit question supplémentaire: Ali, dans la méthode que tu m'as donné pour ajouter une méthode à  NSObject: Ca signifie quoi le @interface NSObject(Debug)? Ce qu'il y a entre parenthèse?
  • schlumschlum Membre
    05:29 modifié #19
    Le retain doit être fait dans le setter...
    Les retain / release doivent être équilibrés dans les accesseurs.

    J'aime pas trop ce "if" inutile à  99,99 % des cas sinon, je trouve cette technique plus simple et plus élégante :

    - (void)setTargetCase:(GWCase*)theCase<br />{<br />	[theCase retain];<br />	[targetCase release];<br />	targetCase = theCase;<br />	targetCase.highLight = YES;<br />}
    

  • AliGatorAliGator Membre, Modérateur
    avril 2009 modifié #20
    dans 1239741101:

    Sinon j'appel le setter comme ceci:
    board.targetCase = [[board caseAtPoint:thePoint] retain];
    

    C'est ok, ça? Faut bien un retain n'est-ce pas?
    Faut bien un retain mais il doit être dans le setter, comme le dit si bien schlum !!! (faut encore que je mette mon lien vers la doc d'Apple sur le Memory Managment ? Vais finir par le mettre en signature >:()

    dans 1239741101:
    [edit] J'ai une petit question supplémentaire: Ali, dans la méthode que tu m'as donné pour ajouter une méthode à  NSObject: Ca signifie quoi le @interface NSObject(Debug)? Ce qu'il y a entre parenthèse?
    Il s'agit d'une catégorie, ça fait partie des possibilités offertes par le langage Objective-C pour étendre les possibilités d'une classe déjà  existante... qui peut s'avérer très pratique

    En l'occurrence j'ajoute une méthode à  la classe existante NSObject (et donc aussi à  toutes les classes dérivant de NSObject, autrement dit toutes les classes de Cocoa en fait) la méthode que tu sembles essayer d'appeler. S'il y a des sous-classes de NSObject qui implémentent cette méthode, ça va la surcharger donc pas de soucis... par contre toutes les autres classes qui à  la base n'implémentent pas cette méthode, bah en rajoutant la catégorie ça va permettent qu'ils y répondent via cette catégorie, et là  du coup en mettant le breakpoint dessus, tu récupères tous ces cas là  (les cas où la méthode est appellée sur un NSObject qui à  la base n'implémentais pas la méthode).

    Pour plus d'infos un peu de lecture : http://developer.apple.com/DOCUMENTATION/Cocoa/Conceptual/ObjectiveC/Articles/ocCategories.html
  • GreensourceGreensource Membre
    05:29 modifié #21
    C'était bien ça le souci, j'avais mal lu la doc et du coup mes setter étais pas bon du tout. Je sais que je fait souvent les mêmes erreurs, je met du temps à  apprendre  :P
    Le souci avec les pointeurs c'est qu'à  la Fac on a commencer par Java, et je pense que ça nous a beaucoup desservi finalement, à  cause de ça. J'ai toujours l'impression que c'est pas si important la gestion de la mémoire alors que ça semble primordial au contraire.
  • schlumschlum Membre
    05:29 modifié #22
    Java mauvais maà®tre... Java poubelle pour l'apprentissage  :crackboom:-
    Puis en fait, il peut y rester, même une fois l'apprentissage terminé  :P
Connectez-vous ou Inscrivez-vous pour répondre.