unrecognized selector sent to instance...

pinuspinus Membre
08:19 modifié dans API AppKit #1
Bonjour,

Je me bats depuis ce matin à  essayer de comprendre pourquoi je me cogne cette erreur. J'appelle une fonction d'un sigleton :
GetColumnListforTable:


La première fois que je l'appelle, aucun souci. La seconde fois (et toutes les fois qui suivent), je reçois le message console suivant :
*** -[DBController GetColumnListforTable:]: unrecognized selector sent to instance 0x141eb0

Pourtant, en pas à  pas dans le debugeur, j'ai bien mon instance (unique) de DBController chargée, avec tout ce qu'il faut dedans. Pourquoi diable ne reconnaà®t-il plus GetColumnListforTable ???

Des pistes où chercher ? je ne sais plus où aller ;-)

D'avance merci.

Pinus.

«1

Réponses

  • Philippe49Philippe49 Membre
    janvier 2009 modifié #2
    Essaie de lire la classe de ton objet NSLog(@%@",[DBController class]);
    0x141eb0 c'est bien l'adresse de DBController ?
  • pinuspinus Membre
    08:19 modifié #3
    dans 1230918850:

    Essaie de lire la classe de ton objet NSLog(@%@",[DBController class]);
    0x141eb0 c'est bien l'adresse de DBController ?


    ça me renvoie bien "DBController" :

    2009-01-02 19:01:15.024 REAL Client[5768:10b] myDBController is not nil
    2009-01-02 19:01:15.024 REAL Client[5768:10b] <DBController: 0x141eb0>
    2009-01-02 19:01:15.025 REAL Client[5768:10b]  classe: DBController
    2009-01-02 19:01:15.028 REAL Client[5768:10b] *** -[DBController GetColumnListforTable:]: unrecognized selector sent to instance 0x141eb0

  • Philippe49Philippe49 Membre
    08:19 modifié #4
    Puisque DBController c'est la classe, ce n'est pas le singleton !

    Il faut donc que ta méthode soit définie avec
    +(....) GetColumnListforTable:....


    ou alors si le singleton est myDBController, il faut faire [myDBController GetColumnListforTable:...]
    avec une méthode
    -(....) GetColumnListforTable:....

    Pour voir l'utilisation des singletons , voir
    file:///Developer/Documentation/DocSets/com.apple.ADC_Reference_Library.CoreReference.docset/Contents/Resources/Documents/documentation/Cocoa/Conceptual/CocoaFundamentals/CocoaObjects/chapter_3_section_1.html
  • pinuspinus Membre
    08:19 modifié #5
    dans 1230919742:

    Puisque DBController c'est la classe, ce n'est pas le singleton !

    Il faut donc que ta méthode soit définie avec
    +(....) GetColumnListforTable:....


    ou alors si le singleton est myDBController, il faut faire [myDBController GetColumnListforTable:...]
    avec une méthode
    -(....) GetColumnListforTable:....

    Pour voir l'utilisation des singletons , voir
    file:///Developer/Documentation/DocSets/com.apple.ADC_Reference_Library.CoreReference.docset/Contents/Resources/Documents/documentation/Cocoa/Conceptual/CocoaFundamentals/CocoaObjects/chapter_3_section_1.html


    J'ai justement écrit mon Singleton par rapport à  cette doc (peut-être me suis-je gouré cela dit).

    J'appelle bien la méthode de mon Singleton comme suit :

    if([myDBController GetColumnListforTable:tableName] == YES){
    


    Auparavant, je récupère une référence à  cette instance de la manière suivante :
    myDBController = [DBController sharedDBController];
    


    J'ai peut-être (probablement !) mal pigé la doc. Mais ce qui m'intrigue, c'est que ça marche nickel la 1ere fois...

    Pinus.


  • Philippe49Philippe49 Membre
    janvier 2009 modifié #6
    dans 1230919392:




    2009-01-02 19:01:15.024 REAL Client[5768:10b] <DBController: 0x141eb0>
    2009-01-02 19:01:15.025 REAL Client[5768:10b]  classe: DBController
    2009-01-02 19:01:15.028 REAL Client[5768:10b] *** -[DBController GetColumnListforTable:]: unrecognized selector sent to instance 0x141eb0
    [/i]



    Erreur
    Revoies la définition de ta classe DBController, et de ce que renvoie la méthode +(DBController) sharedDBController.

  • pinuspinus Membre
    janvier 2009 modifié #7
    dans 1230921024:

    dans 1230919392:




    2009-01-02 19:01:15.024 REAL Client[5768:10b] <DBController: 0x141eb0>
    2009-01-02 19:01:15.025 REAL Client[5768:10b]  classe: DBController
    2009-01-02 19:01:15.028 REAL Client[5768:10b] *** -[DBController GetColumnListforTable:]: unrecognized selector sent to instance 0x141eb0
    [/i]



    Erreur
    Revoies la définition de ta classe DBController, et de ce que renvoie la méthode +(DBController) sharedDBController.


    Je comprends bien ce que tu m'expliques. ça sonne assez "logique". Pourtant, je ne renvoie dans "sharedDBController" rien d'autre qu'une instance "shared" de la classe DBController. Du reste, lors du premier appel à  la méthode "GetColumnListforTable:", je n'ai aucune erreur. Ce sont les appels suivant qui retournent cette erreur.

    Bien entendu que j'ai dû faire une ânerie. C'est évident. Mais après une journée pleine passé dessus, je n'arrive pas à  voir où je me plante.

    voici mes méthodes de classe (si ça te parle) :
    <br />static DBController *shared = nil;<br /><br />+(id) sharedDBController{<br />&nbsp; @synchronized(self) {<br />	if(!shared){<br />		//shared = [[self alloc] init];<br />		[[self alloc] init];<br />	}<br />&nbsp; }<br />	return shared;<br />}<br /><br />+ (id)allocWithZone:(NSZone *)zone<br />{<br />&nbsp; &nbsp; @synchronized(self) {<br />&nbsp; &nbsp; &nbsp; &nbsp; if (shared == nil) {<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; shared = [super allocWithZone:zone];<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return shared;&nbsp; // assignment and return on first allocation<br />&nbsp; &nbsp; &nbsp; &nbsp; }<br />&nbsp; &nbsp; }<br />&nbsp; &nbsp; return nil; //on subsequent allocation attempts return nil<br />}<br />
    


    En tout état de cause, merci pour ton aide, elle m'est précieuse !

    Pinus.
  • AliGatorAliGator Membre, Modérateur
    08:19 modifié #8
    dans 1230922260:
    +(id) sharedDBController{<br />  @synchronized(self) {<br />	if(!shared){<br />		//shared = [[self alloc] init];<br />		[[self alloc] init];<br />	}<br />  }<br />  return shared;<br />}
    

    Je sais pas si ça changera grand chose, mais ta méthode [tt]sharedDBController[/tt] devrait avoir [tt](DBController*)[/tt] comme type de retour et pas [tt](id)[/tt]...
  • Philippe49Philippe49 Membre
    08:19 modifié #9
    Cela ressemble à  un message envoyé à  un objet qui a été "released"
    As-tu codé aussi release et autorelease comme indiqué afin d'éviter une destruction du singleton ?


    (id)copyWithZone:(NSZone *)zone
    {
       return self;
    }

    - (id)retain
    {
       return self;
    }

    - (unsigned)retainCount
    {
       return UINT_MAX;  //denotes an object that cannot be released
    }

    - (void)release
    {
       //do nothing
    }

    - (id)autorelease
    {
       return self;
    }
  • Philippe49Philippe49 Membre
    janvier 2009 modifié #10
    dans 1230923555:

    Je sais pas si ça changera grand chose, mais ta méthode [tt]sharedDBController[/tt] devrait avoir [tt](DBController*)[/tt] comme type de retour et pas [tt](id)[/tt]...

    Oui le problème peut être que myDBController (=shared)  est créé par [super allocWithZone:zone], et qu'ainsi son champ isa n'est pas celui d'un DBController.


    Ben non, c'est le init qui précise la classe , voir post suivant.
  • Philippe49Philippe49 Membre
    janvier 2009 modifié #11
    Essai  négatif :
    % gcc pgm.m -o pgm -framework Foundation
    % pgm
    2009-01-02 20:35:46.544 pgm[2408:10b] SingletonClass
    %

    <br />#import &lt;Foundation/Foundation.h&gt;<br /><br />@interface SingletonClass:NSObject {<br />}<br />-(void)print;<br />@end<br /><br />static SingletonClass *shared = nil;<br />@implementation SingletonClass<br /><br />+ (id )sharedObject<br />{<br />	@synchronized(self) {<br />		if (shared == nil) {<br />			[[self alloc] init]; // assignment not done here<br />		}<br />	}<br />	return shared;<br />}<br /><br />+ (id)allocWithZone:(NSZone *)zone<br />{<br />	@synchronized(self) {<br />		if (shared == nil) {<br />			shared = [super allocWithZone:zone];<br />			return shared;&nbsp; // assignment and return on first allocation<br />		}<br />	}<br />	return nil; //on subsequent allocation attempts return nil<br />}<br /><br />- (id)copyWithZone:(NSZone *)zone<br />{<br />	return self;<br />}<br /><br />- (id)retain<br />{<br />	return self;<br />}<br /><br />- (unsigned)retainCount<br />{<br />	return UINT_MAX;&nbsp; //denotes an object that cannot be released<br />}<br /><br />- (void)release<br />{<br />	//do nothing<br />}<br /><br />- (id)autorelease<br />{<br />	return self;<br />}<br />-(void)print{<br />	NSLog(@&quot;coucou&quot;);<br />}<br />@end<br />int main(int argc, char *argv&#91;]) {<br />	<br />	NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];<br />	id shared=[SingletonClass sharedObject];<br /><br />	NSLog(@&quot;%@&quot;, [shared class]);<br />	[shared print];<br />	[shared print];<br />	[pool drain]; <br />	return 0;<br />}<br />
    


  • pinuspinus Membre
    08:19 modifié #12
    dans 1230923555:

    Je sais pas si ça changera grand chose, mais ta méthode [tt]sharedDBController[/tt] devrait avoir [tt](DBController*)[/tt] comme type de retour et pas [tt](id)[/tt]...
    [/quote]

    Non, ça ne joue pas. Mais merci quand même ! ;-)

    Pinus.
  • pinuspinus Membre
    08:19 modifié #13
    dans 1230923646:

    Cela ressemble à  un message envoyé à  un objet qui a été "released"
    As-tu codé aussi release et autorelease comme indiqué afin d'éviter une destruction du singleton ?


    (id)copyWithZone:(NSZone *)zone
    {
       return self;
    }

    - (id)retain
    {
       return self;
    }

    - (unsigned)retainCount
    {
       return UINT_MAX;  //denotes an object that cannot be released
    }

    - (void)release
    {
       //do nothing
    }

    - (id)autorelease
    {
       return self;
    }



    Oui, j'ai implémenté ces méthodes également.

    Pinus.
  • Philippe49Philippe49 Membre
    08:19 modifié #14
    Le code du post ci-dessus marche. Cela ne semble pas dans le singleton, mais une désallocation quelque part dans ton code.( le shared peut continuer à  pointer vers une adresse où il n'y a plus ce qui a été mis au départ)
  • pinuspinus Membre
    08:19 modifié #15
    dans 1230926915:

    Le code du post ci-dessus marche. Cela ne semble pas dans le singleton, mais une désallocation quelque part dans ton code.( le shared peut continuer à  pointer vers une adresse où il n'y a plus ce qui a été mis au départ)


    J'y ai bien pensé, car cette idée de "désallocation" me paraà®t la plus probable (puisque tout fonctionne correctement lors de la première exécution), mais je ne vois pas comment c'est possible : en exécutant pas à  pas dans le debuger, j'ai bien TOUJOURS mon instance valide où je peux voir que mes variables sont valides elles aussi, et alimentées. Je veux bien que cette instance pointe au diable, mais si c'était le cas, je ne verrais pas mes 2 NSArray instanciés et initialisées correctement.

    J'ai l'impression que je me suis mis dans un sacré pétrin ;-)


  • pinuspinus Membre
    08:19 modifié #16
    dans 1230928787:

    dans 1230926915:

    Le code du post ci-dessus marche. Cela ne semble pas dans le singleton, mais une désallocation quelque part dans ton code.( le shared peut continuer à  pointer vers une adresse où il n'y a plus ce qui a été mis au départ)


    J'y ai bien pensé, car cette idée de "désallocation" me paraà®t la plus probable (puisque tout fonctionne correctement lors de la première exécution), mais je ne vois pas comment c'est possible : en exécutant pas à  pas dans le debuger, j'ai bien TOUJOURS mon instance valide où je peux voir que mes variables sont valides elles aussi, et alimentées. Je veux bien que cette instance pointe au diable, mais si c'était le cas, je ne verrais pas mes 2 NSArray instanciés et initialisées correctement.

    J'ai l'impression que je me suis mis dans un sacré pétrin ;-)



    On dirait que c'est l'appel en (lui-même) à  la fonction, qui fait tout partir en vrille car si j'exécute cette ligne :
    [myDBController.dbTableFields removeAllObjects];
    

    ..elle est exécutée sans problème..

    et la ligne qui suit immédiatement :
    [myDBController GetColumnListforTable:tableName];
    

    arrête tout et me log l'erreur "unrecognized selector sent..."

    ..et ce, à  partir de la seconde exécution.

    J'avoue que j'en perds mon Latin...

  • psychoh13psychoh13 Mothership Developer Membre
    08:19 modifié #17
    À mon avis tu devrais nous envoyer ton projet pour nous permettre de voir par nos yeux ce qu'il se passe réellement dans ton code...






    PS : beurk les noms de tes classes...
  • Philippe49Philippe49 Membre
    08:19 modifié #18
    Tu nous aurais pas fait le coup
    GetColumnListforTable <-> GetColumnListForTable  ??


    Autrement quel est le prototype de cette méthode ?
  • pinuspinus Membre
    08:19 modifié #19
    dans 1230932486:

    À mon avis tu devrais nous envoyer ton projet pour nous permettre de voir par nos yeux ce qu'il se passe réellement dans ton code...


    Le projet ne pourra pas être exécuté puisqu'il se connecte à  une base de données sur mon réseau.

    Mais en bref :

    ma classe DBController est le singleton en question, à  partir de laquelle je tape dans ma base de données.

    Dans mon appli, je fais ça (à  partir d'une autre classe) :
    <br />myDBController = [DBController sharedDBController];<br />[myDBController.dbTableFields removeAllObjects];<br />if([myDBController GetColumnListforTable:tableName])<br />		[fieldsTable reloadData];<br />
    


    La 1ere fois que c'est exécuté, aucun souci.
    dès la seconde fois, je me cogne l'erreur en question, bien que myDBController est parfaitement instancié et que j'ai accès aux variables d'instance (par ex : [myDBController.dbTableFields removeAllObjects];).



    dans 1230932486:

    PS : beurk les noms de tes classes...


    En même temps, je ne cherche pas à  faire un concours de style. Par ailleurs, les questions de goût... c'est toujours très subjectif. Mais je te promets de faire un effort une fois que j'aurais "réglé" mon problème ;-)

    En tout éta de cause, merci.
  • psychoh13psychoh13 Mothership Developer Membre
    08:19 modifié #20
    Il n'y a que trois possibilités, la première c'est que tu as mal orthographié le nom de ta méthode, mais à  ce moment-là , le compilateur devrait au moins te faire un warning, la deuxième possibilité c'est que ton objet a changé pendant l'exécution, la dernière solution c'est que la méthode a été supprimée au passage pendant l'exécution...

    Ces trois possibilités sont tout aussi improbables les unes que les autres...
    Et le débogueur ne sera pas capable de t'aider.

    Les tests à  faire sont plutôt simples... La première tu effaces le nom et tu fais un copier/coller du nom dans le .m, pour la deuxième, tu fais un NSLog(@%p, myDBController); avant l'exécution de la méthode et tu vérifies si l'adresse ne change pas. Et dernière vérification, tu la fais avec la méthode respondsToSelector: tu devrais aussi utiliser les fonctions disponibles dans le runtime directement.

    La seule solution que je vois pour l'instant, c'est créer un nouveau projet et copier tes sources d'un projet à  l'autre, des fois, voire souvent, ça corrige les bogues inexpliqués...


    PS: Sinon ce n'est pas une question de style, c'est plutôt une question de conventions, mais bon peu importe.
  • Philippe49Philippe49 Membre
    08:19 modifié #21
    dans 1230934787:


    La 1ere fois que c'est exécuté, aucun souci.
    dès la seconde fois, je me cogne l'erreur en question, bien que myDBController est parfaitement instancié et que j'ai accès aux variables d'instance (par ex : [myDBController.dbTableFields removeAllObjects];).


    Non , Objective.C permet d'envoyer des messages à  nil .
    Le fait qu'il ne râle pas sur [myDBController.dbTableFields removeAllObjects] ne prouve pas l'existence de myDBController.



    ===========================================================

    #import <Foundation/Foundation.h>

    @interface ClassA:NSObject {
    NSMutableArray * table;
    }
    @property(nonatomic,retain) NSMutableArray * table;
    -(void)print;
    @end



    @implementation ClassA
    @synthesize table;
    -(void)print{
    NSLog(@%@",table);
    }
    @end

    int main(int argc, char *argv[]) {

    NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
    ClassA * a=[[ClassA alloc] init];
    a.table=[NSMutableArray arrayWithObjects:@un,@deux,nil]; 
    [a print];

    a=nil;
    [a.table removeAllObjects];
    NSLog(@%@",a.table);

    [pool drain];
    return 0;
    }



    % gcc pgm2.m -o pgm -framework Foundation
    % pgm
    2009-01-02 23:56:58.815 pgm[647:10b] (
        un,
        deux
    )
    2009-01-02 23:56:58.817 pgm[647:10b] (null)

  • AliGatorAliGator Membre, Modérateur
    janvier 2009 modifié #22
    Vu que ce n'est qu'à  la seconde exécution, essaye d'écrire (qqpart au début de ton programme, pour ne pas mélanger ces appels de test avec le reste et les appels que tu fais normalement) ceci :
    NSLog(@&quot;1er appel = %@&quot; ,[DBController sharedDBController]);<br />NSLog(@&quot;2e appel = %@&quot; ,[DBController sharedDBController]);
    
    et vérifie que les deux fois il te donne les mêmes adresses.

    Tu peux aussi essayer un
    DBController* myDBController;<br />myDBController = [DBController sharedDBController];<br />NSLog(@&quot;1er appel = %@ (%@)&quot; ,myDBController, [myDBController className]);<br />myDBController = [DBController sharedDBController];<br />NSLog(@&quot;2e appel = %@ (%@)&quot; ,myDBController, [myDBController className]);
    


    [EDIT]Bon je viens de relire psychoh13, c'est plus ou moins ce qu'il te conseille de faire aussi comme test pour l'un de ses 3 cas en fait ^^[/EDIT]
  • pinuspinus Membre
    08:19 modifié #23
    dans 1230937112:

    Non , Objective.C permet d'envoyer des messages à  nil .
    Le fait qu'il ne râle pas sur [myDBController.dbTableFields removeAllObjects] ne prouve pas l'existence de myDBController.
    ...


    Oui, complètement. Mais le simple fait que, exécutant :
    [myDBController.dbTableFields removeAllObjects];
    

    ... myDBController.dbTableFields passe de 124 objets à  0, tend à  m'inspirer sur le fait que mon instance existe bel et bien. Non ?
  • pinuspinus Membre
    08:19 modifié #24
    dans 1230938649:

    Vu que ce n'est qu'à  la seconde exécution, essaye d'écrire (qqpart au début de ton programme, pour ne pas mélanger ces appels de test avec le reste et les appels que tu fais normalement) ceci :
    NSLog(@&quot;1er appel = %@&quot; ,[DBController sharedDBController]);<br />NSLog(@&quot;2e appel = %@&quot; ,[DBController sharedDBController]);
    
    et vérifie que les deux fois il te donne les mêmes adresses.


    2009-01-03 00:41:47.700 REAL Client[7339:813] 1er appel = <DBController: 0x141d70>
    2009-01-03 00:41:47.710 REAL Client[7339:813] 2e appel = <DBController: 0x141d70>
    2009-01-03 00:41:47.713 REAL Client[7339:813] 3e appel = <DBController: 0x141d70>
    2009-01-03 00:41:47.713 REAL Client[7339:813] 4e appel = <DBController: 0x141d70>

    merci.
  • pinuspinus Membre
    08:19 modifié #25
    dans 1230935822:

    ....
    Les tests à  faire sont plutôt simples... La première tu effaces le nom et tu fais un copier/coller du nom dans le .m, pour la deuxième, tu fais un NSLog(@%p, myDBController); avant l'exécution de la méthode et tu vérifies si l'adresse ne change pas. Et dernière vérification, tu la fais avec la méthode respondsToSelector: tu devrais aussi utiliser les fonctions disponibles dans le runtime directement.


    Les 3 ne m'apprenent rien de plus :-( Tout à  l'air normal, si ce n'est que cette méthode n'est plsu reconnue dès le second appel.



    La seule solution que je vois pour l'instant, c'est créer un nouveau projet et copier tes sources d'un projet à  l'autre, des fois, voire souvent, ça corrige les bogues inexpliqués...


    Oui, et bien je crois qu'il n'y a plus que ça. J'imagine que je dois faire une belle connerie quelque part, mais là , ça devient nébuleux ;-)


    PS: Sinon ce n'est pas une question de style, c'est plutôt une question de conventions, mais bon peu importe.


    Autant pour moi alors ;-)
  • pinuspinus Membre
    08:19 modifié #26
    dans 1230938649:

    Tu peux aussi essayer un
    DBController* myDBController;<br />myDBController = [DBController sharedDBController];<br />NSLog(@&quot;1er appel = %@ (%@)&quot; ,myDBController, [myDBController className]);<br />myDBController = [DBController sharedDBController];<br />NSLog(@&quot;2e appel = %@ (%@)&quot; ,myDBController, [myDBController className]);
    



    2009-01-03 00:48:35.989 REAL Client[7383:813] 1er appel = <DBController: 0x141d70> (DBController)
    2009-01-03 00:48:35.991 REAL Client[7383:813] 2e appel = <DBController: 0x141d70> (DBController)

    Merci.
  • Philippe49Philippe49 Membre
    janvier 2009 modifié #27
    On serait en pur C, je penserais aux effets de bords : on écrit trop loin dans une zone mémoire, et on écrase de la mémoire déjà  utilisée ...
    Avec ta base de données qui doit être conséquente, tu n'as pas de débordement incontrôlé ?

    Par exemple, avec le projet Cocoa ci-dessous, l'exécution plante au bout du troisième appel sur le bouton, et gdb me dit que c'est dans une méthode graphique que cela plante ...

    #import "AppController.h"
    #import "SingletonClass.h"
    static char *str;
    @implementation AppController
    -(void) awakeFromNib {
    SingletonClass* shared=[SingletonClass sharedObject];
    shared.table=[NSArray arrayWithObjects:@un,@deux,nil]; 
    str=malloc(100);
    }
    -(IBAction) buttonAction:(id)sender {
    SingletonClass* shared=[SingletonClass sharedObject];
    NSLog([shared className]);
    [shared print];
    str=memset(str,'o',110)+110;
    }
    @end
  • psychoh13psychoh13 Mothership Developer Membre
    08:19 modifié #28
    Je confirme ce que dit Aligator, le fait que GDB affiche quelque ne signifie pas que l'objet est valide... ça signifie juste que GDB n'a pas fait planter le programme quand il a regardé sa mémoire... Les seuls tests valides c'est avec le runtime, par exemple la fonction du runtime :
    NSLog(@&quot;%p&quot;, class_getInstanceMethod([myObject class], @selector(myMethod)));
    


    ou encore :
    NSLog(@&quot;%s&quot;, object_getClassName(myObject));
    


    Avec ça tu auras des tests fiables...

    Ensuite, tu vas répliquer que tu t'occuperas du style après, mais ça, ça fait partie des bonnes habitudes à  prendre... Il vaut mieux éviter de permettre à  du code externe, même si c'est le tien, de pouvoir modifier le contenu d'un objet, sans passer par l'objet lui-même...
    Je pense en particulier à  ta propriété qui permet de récupérer un NSMutableArray et à  qui tu envoies le message removeAllObjects.
    Non seulement c'est anti-programmation objet, mais c'est aussi plutôt dangereux, il vaut mieux une méthode intermédiaire qui te permette de filtre les différentes actions que tu fais sur tel objet, ce sera déjà  beaucoup facile à  maintenir et les comportements seront concentrés dans une seule classe.
    Alors que permettre aux autres objets d'accéder et de modifier le contenu des variables d'instances sans passer par l'objet c'est plus aléatoire...
    Je dis ça par expérience, je me suis évité plein d'emmerdes à  écrire des méthodes proxy pour gérer les ivars de mes objets, et pour récupérer les données des objets modifiables comme des NSMutableDictionary ou NSMutableArray, même si le code ne dépasse pas ma juridiction, je retourne des copies...
    ça limite les comportements inattendus, et ça évite de se perdre quand on écrit plusieurs milliers de lignes de code sur plusieurs séances...
  • pinuspinus Membre
    08:19 modifié #29
    dans 1230946574:

    Je confirme ce que dit Aligator, le fait que GDB affiche quelque ne signifie pas que l'objet est valide... ça signifie juste que GDB n'a pas fait planter le programme quand il a regardé sa mémoire... Les seuls tests valides c'est avec le runtime, par exemple la fonction du runtime :
    NSLog(@&quot;%p&quot;, class_getInstanceMethod([myObject class], @selector(myMethod)));
    


    ou encore :
    NSLog(@&quot;%s&quot;, object_getClassName(myObject));
    


    Avec ça tu auras des tests fiables...


    OK, je vais tester avec ça. Merci. Non mais loin de moi l'idée de contredire Aligator (d'autant que c'est Philippe49 qui causait), "j'dis juste" (comme dirait les Deschiens) qu'en debug, je vois mon instance et que les données qu'elle contient sont celles qui sont censées y être. Maintenant, en effet, je ne suis certain de rien...


    Ensuite, tu vas répliquer que tu t'occuperas du style après, mais ça, ça fait partie des bonnes habitudes à  prendre... Il vaut mieux éviter de permettre à  du code externe, même si c'est le tien, de pouvoir modifier le contenu d'un objet, sans passer par l'objet lui-même...
    Je pense en particulier à  ta propriété qui permet de récupérer un NSMutableArray et à  qui tu envoies le message removeAllObjects.
    Non seulement c'est anti-programmation objet, mais c'est aussi plutôt dangereux, il vaut mieux une méthode intermédiaire qui te permette de filtre les différentes actions que tu fais sur tel objet, ce sera déjà  beaucoup facile à  maintenir et les comportements seront concentrés dans une seule classe.
    Alors que permettre aux autres objets d'accéder et de modifier le contenu des variables d'instances sans passer par l'objet c'est plus aléatoire...


    Aucune propriété de ma classe n'est modifié de l'extérieur. En fait, j'ai ajouté cette ligne pour des raisons de test: cela fait 2 jours que j'essaie de trouver d'où vient cette blague. Donc j'ai essayé plein de trucs. Donc je respectais bien l'encapsulation. Cela dit, il s'agit de propriétés synthétisées. Et la syntaxe monInstance.mavar n'est rien d'autre qu'un accesseur (mavar/setMavar). Cela dit, cette ligne n'était là  que pour des raisons de test.


    Je dis ça par expérience, je me suis évité plein d'emmerdes à  écrire des méthodes proxy pour gérer les ivars de mes objets, et pour récupérer les données des objets modifiables comme des NSMutableDictionary ou NSMutableArray, même si le code ne dépasse pas ma juridiction, je retourne des copies...
    ça limite les comportements inattendus, et ça évite de se perdre quand on écrit plusieurs milliers de lignes de code sur plusieurs séances...


    J'en prends note. Merci bien.

    Pinus.

  • pinuspinus Membre
    08:19 modifié #30
    dans 1230946574:

    ...
    NSLog(@&quot;%p&quot;, class_getInstanceMethod([myObject class], @selector(myMethod)));
    


    ou encore :
    NSLog(@&quot;%s&quot;, object_getClassName(myObject));
    

    ...


    Les résultats sont très intéressant (voir pour moi : hallucinant):

    -1ère exécution :

    2009-01-03 11:35:18.476 REAL Client[7729:813] populateColums for :personnes
    2009-01-03 11:35:26.473 REAL Client[7729:813] logX: 0x141d70  <
    NSLog(@logX: %p, myDBController);
    2009-01-03 11:35:27.391 REAL Client[7729:813] 0x144ab0   <
    NSLog(@%p, class_getInstanceMethod([myDBController class], @selector(GetColumnListForTable:)));
    2009-01-03 11:35:28.206 REAL Client[7729:813] DBController  <
    NSLog(@%s, object_getClassName(myDBController));
    2009-01-03 11:35:31.613 REAL Client[7729:813] executing query : PRAGMA table_info(personnes)
    2009-01-03 11:35:31.687 REAL Client[7729:813] getting 124 rows

    -2eme exécution :

    2009-01-03 11:35:36.908 REAL Client[7729:813] populateColums for :tels_pro
    2009-01-03 11:35:39.532 REAL Client[7729:813] logX: 0x141d70  <
    NSLog(@logX: %p, myDBController);
    2009-01-03 11:35:39.532 REAL Client[7729:813] 0x0  <
    NSLog(@%p, class_getInstanceMethod([myDBController class], @selector(GetColumnListForTable:)));
    2009-01-03 11:35:39.533 REAL Client[7729:813] DBController  <
    NSLog(@%s, object_getClassName(myDBController));
    2009-01-03 11:35:39.533 REAL Client[7729:813] *** -[DBController GetColumnListForTable:]: unrecognized selector sent to instance 0x141d70
    2009-01-03 11:35:39.534 REAL Client[7729:813] *** -[DBController GetColumnListForTable:]: unrecognized selector sent to instance 0x141d70

    Il semble que j'ai bien toujours mon instance mais que celle-ci, à  la seconde exec, ne soit plus capable de gérer la méthode "GetColumnListForTable:". Moi, en tant que débutant, ça me calme....

    Pinus...


  • Philippe49Philippe49 Membre
    janvier 2009 modifié #31
    Une autre piste de recherche : le debugger permet de voir ce qui se passe en mémoire
    (mettre des breakpoints sur myDBController=[DBController sharedController], et utiliser une option de menu contextuel)

Connectez-vous ou Inscrivez-vous pour répondre.