methodes de classe et d'instance dans un singleton

bofybofy Membre
00:30 modifié dans API AppKit #1
Bonjour (me voici de retour...)

Je crée un singleton Common : NSObject

Je crée une méthode d'instance
<br />-(void) toto {<br />	NSLog(@&quot;setTotoc.in&quot;);<br />}<br />


Je fais
<br />Common * common = [[Common alloc] init];<br />[common toto];<br />


J'imaginais que "setTotoc.in" allait s'afficher dans la console : rien.

Par contre si je crée toto en méthode de classe (+ au lieu de -)
ça marche.

Où est mon erreur ?

Merci

Réponses

  • NoNo Membre
    00:30 modifié #3
    dans 1223217144:

    Je crée un singleton Common : NSObject

    Créer un singleton, ça ne veut rien dire.
    Utiliser le paradigme singleton au niveau de cocoa (et de beaucoup d'autres langages objet), c'est s'assurer (lors de la conception de la classe) qu'une seule instance ne peut exister, et qu'elle est, à  tout moment, accessible.

    dans 1223217144:

    J'imaginais que "setTotoc.in" allait s'afficher dans la console : rien.
    Par contre si je crée toto en méthode de classe (+ au lieu de -)
    ça marche.
    Où est mon erreur ?

    Avec le peu de code que tu donnes, difficile de dire...
    Peut-être as tu simplement fais une faute dans l'écriture de common. Le simple fait d'oublier ou d'ajouter une majuscule à  ce mot common fait que soit tu utilises l'instance, soit tu utilises la classe...
    C'est pourquoi il n'est pas toujours souhaitable d'avoir des noms d'instance et de classe similaires...

    C'est aussi pourquoi certains ici (schlum, aligator ou philippe pour nommer les plus actifs) sont pointilleux sur "l'orthographe" des noms de classe, d'instance et de variable.
  • bofybofy Membre
    00:30 modifié #4
    dans 1223218769:


    Merci, c'est sympa ; mais ça fait des jours que j'ai cette doc sur mon bureau...
  • bofybofy Membre
    00:30 modifié #5
    dans 1223223210:

    dans 1223217144:

    Je suis tout à  fait d'accord avec l'importance de l'orthographe, mais ce n'est quand même qu'une convention communautaire d'écriture, rien de plus qu'une convention... Depuis que je pratique le C, dans une autre vie, je ne confonds plus minuscules et majuscules.

    Bon, voici un peu plus de code. Je précise que Common est construit selon le "paradigme" singleton

    <br />@interface Common : NSObject {<br />+(void) setToto;<br />-(void) toto;<br />@implementation Common<br />-(void) toto {<br />	NSLog(@&quot;setTotoc.in&quot;);<br />}<br />+(void) setToto {<br />	NSLog(@&quot;setTotoC.in&quot;);<br />}<br />#import &quot;Common.h&quot;<br />	Common * common = [[Common alloc] init];<br />	[common toto];<br />	[Common setToto];<br />...<br />
    


    Je crée un singleton Common : NSObject

    Créer un singleton, ça ne veut rien dire.
    Utiliser le paradigme singleton au niveau de cocoa (et de beaucoup d'autres langages objet), c'est s'assurer (lors de la conception de la classe) qu'une seule instance ne peut exister, et qu'elle est, à  tout moment, accessible.

    dans 1223217144:

    J'imaginais que "setTotoc.in" allait s'afficher dans la console : rien.
    Par contre si je crée toto en méthode de classe (+ au lieu de -)
    ça marche.
    Où est mon erreur ?

    Avec le peu de code que tu donnes, difficile de dire...
    Peut-être as tu simplement fais une faute dans l'écriture de common. Le simple fait d'oublier ou d'ajouter une majuscule à  ce mot common fait que soit tu utilises l'instance, soit tu utilises la classe...
    C'est pourquoi il n'est pas toujours souhaitable d'avoir des noms d'instance et de classe similaires...

    C'est aussi pourquoi certains ici (schlum, aligator ou philippe pour nommer les plus actifs) sont pointilleux sur "l'orthographe" des noms de classe, d'instance et de variable.
  • Philippe49Philippe49 Membre
    octobre 2008 modifié #6
    Ton erreur semble ailleurs, dans la manière de définir ton singleton sans doute

    [size=12pt]Essai[/size]
    #import <Foundation/Foundation.h>
    @interface Common : NSObject {
    }
    +(void) setToto;
    -(void) toto;
    @end

    @implementation Common
    -(void) toto {
    NSLog(@setTotoc.in);
    }
    +(void) setToto {
    NSLog(@setTotoC.in);
    }
    @end

    int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool=[[NSAutoreleasePool alloc] init];
    Common * common = [[Common alloc] init];
    [common toto];
    [Common setToto];
    [pool drain];
    return 0;
    }


    [size=12pt]Résultat[/size]

    % gcc pgm.m -o pgm -framework Foundation
    % pgm
    2008-10-06 14:09:59.424 pgm[1437:10b] setTotoc.in
    2008-10-06 14:09:59.426 pgm[1437:10b] setTotoC.in
    %

  • bofybofy Membre
    00:30 modifié #7
    dans 1223295104:

    Ton erreur semble ailleurs, dans la manière de définir ton singleton sans doute


    C'est probable !

    Après de multiples essais, il semble que les méthodes d'instance marchent dans un singleton, lorsque
        - 1. on ne déclare pas la méthode de classe +sharedInstance (ou autre écriture) dans l'implementation
        - 2. on n'appelle pas ladite méthode de classe: pas de [Singleton sharedInstance]

    Où est mon erreur ? J'aimerais comprendre ?

    #import &lt;Cocoa/Cocoa.h&gt;<br />#import &quot;STDClass.h&quot;<br />#import &quot;SGLTClass.h&quot;<br /><br />int main(int argc, char *argv&#91;]) {<br />	NSLog(@&quot;========&gt;&quot;); // marque début application<br />	NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init]; // sinon des tas de messages dans la console...<br />	[NSApplication sharedApplication]; <br />	//--------<br />	STDClass * stdClass = [[STDClass alloc] init];<br />	[stdClass getVal];<br />	[stdClass setVal];<br />	//--------<br />//	[SGLTClass sharedInstance];<br />	SGLTClass * sgltClass = [[SGLTClass alloc] init];<br />	[sgltClass getVal];<br />	[sgltClass setVal];<br />	//--------<br />	[NSApp run];<br />	[pool release]; // libération du pool<br />	return 0;<br />}<br />
    


    #import &lt;Cocoa/Cocoa.h&gt;<br /><br /><br />@interface SGLTClass : NSObject {<br /><br />}<br />//+(SGLTClass *)sharedInstance;<br /><br />-(id) getVal;<br /><br />-(void) setVal;<br /><br />@end<br />
    


    #import &quot;SGLTClass.h&quot;<br /><br />static SGLTClass * addressInstance = nil;<br /><br /><br />@implementation SGLTClass<br />+(SGLTClass *)sharedInstance {<br /> //----------------<br /> @synchronized(self) {<br />	 if (addressInstance == nil) {<br />		 [[self alloc] init];<br />		}<br />	}<br /> return addressInstance;<br /> //----------------<br /> }<br /> <br /> +(id)allocWithZone:(NSZone *)zone{<br /> @synchronized(self) {<br /> if (addressInstance == nil) {<br /> addressInstance = [super allocWithZone:zone];<br /> return addressInstance;<br /> }<br /> }<br /> return nil;<br /> }<br /><br /><br />-(id) getVal {<br />	NSLog(@&quot;getValSGLT.in&quot;);<br />	return self;<br />}<br /><br />-(void) setVal{<br />	NSLog(@&quot;setValSGLT.in&quot;);<br />}<br /><br /><br />-(id)copyWithZone: (NSZone *)zone {<br />	return self;<br />}<br /><br />-(id)retain {<br />	return self;<br />}<br /><br />-(unsigned)retainCount {<br />	return UINT_MAX; //denotes an object that cannot be released<br />}<br /><br />-(void)release {<br />	//do nothing<br />}<br /><br />-(id)autorelease {<br />	return self;<br />}<br /><br /><br />@end<br />
    


    #import &lt;Cocoa/Cocoa.h&gt;<br /><br /><br />@interface STDClass : NSObject {<br /><br />}<br />-(id) getVal;<br />-(void) setVal;<br /><br />@end<br />
    


    #import &quot;STDClass.h&quot;<br /><br /><br />@implementation STDClass<br /><br />-(id) getVal {<br />	NSLog(@&quot;getValSTD.in&quot;);<br />	return self;<br />}<br /><br />-(void) setVal{<br />	NSLog(@&quot;setValSTD.in&quot;);<br />}<br /><br />@end<br />
    

  • Philippe49Philippe49 Membre
    octobre 2008 modifié #8
    Il faut remplacer

    // [SGLTClass sharedInstance];
    SGLTClass * sgltClass = [[SGLTClass alloc] init];

    par

    SGLTClass * sgltClass = [SGLTClass sharedInstance];


  • bofybofy Membre
    00:30 modifié #9
    Apparemment, ça marche.

    Merci.

    Mais je comprends mal pourquoi
    SGLTClass * sgltClass = [[SGLTClass alloc] init];
    

    masque des méthodes d'instance !
    Avec une classe standard, chaque instance créée a accès à  toutes les méthodes d'instance définies dans la classe, non ?

    Problème d'adresse ? il y a une subtilité ou une montagne qui m'échappe.

    dans 1223474004:

    Il faut remplacer

    // [SGLTClass sharedInstance];
    SGLTClass * sgltClass = [[SGLTClass alloc] init];

    par

    SGLTClass * sgltClass = [SGLTClass sharedInstance];



  • bofybofy Membre
    00:30 modifié #10
    re-moi !

    en faisant des nouveaux essais, je pense que c'est la présence dans l'ordre des deux lignes
    [SGLTClass sharedInstance];<br />	SGLTClass * sgltClass = [[SGLTClass alloc] init];<br />
    

    qui pose problème : d'ailleurs sgltClass == (null)

    Si j'écris
    SGLTClass * sgltClass = [[SGLTClass alloc] init];<br />	[SGLTClass sharedInstance];
    

    ça marche (y compris pour les adresses du singleton, qui sont bien les mêmes)

    Mais je n'en comprends pas plus... Pourquoi l'instance "sgltClass" n'est-elle pas initialisée de la même façon dans les deux cas ?

    En tout cas, je retiens qu'avec les singletons, il ne faut pas utiliser directement l'initialisation classique [[ClassName alloc] init] ; c'est bien ça ?

    dans 1223474004:

    Il faut remplacer

    // [SGLTClass sharedInstance];
    SGLTClass * sgltClass = [[SGLTClass alloc] init];

    par

    SGLTClass * sgltClass = [SGLTClass sharedInstance];



  • Philippe49Philippe49 Membre
    00:30 modifié #11
    La méthode alloc appelle automatiquement allocWithZone.
    Voilà  ta méthode allocWithZone :

    +(id)allocWithZone:(NSZone *)zone{
    @synchronized(self) {
    if (addressInstance == nil) {
    addressInstance = [super allocWithZone:zone];
    return addressInstance;
    }
    }
    return nil;
    }


    Si addressInstance n'est pas nul, cette méthode renvoie nil, ainsi pour
    [SGLTClass sharedInstance];
    SGLTClass * sgltClass = [[SGLTClass alloc] init];

    la première instruction crée la sharedInstance, donc la deuxième fait que sgltClass=nil.

    Si addressInstance est nul, addressInstance est construit puis renvoyé. Ainsi,
    SGLTClass * sgltClass = [[SGLTClass alloc] init];
    [SGLTClass sharedInstance];

    la première instruction crée la sharedInstance, et l'affecte à  sgltClass, la deuxième l'appelle sans passer par allocWithZone, sans rien faire finalement.

    dans 1223557716:

    En tout cas, je retiens qu'avec les singletons, il ne faut pas utiliser directement l'initialisation classique [[ClassName alloc] init] ; c'est bien ça ?


    [size=12pt]OUI[/size]



  • bofybofy Membre
    00:30 modifié #12
    Résolu pour moi

    Je comprends, à  peu près...

    Reste que la notion de singleton me paraà®t essentielle, alors qu'elle est pauvrement documentée.

    Merci et à  bientôt.

    dans 1223558552:

    La méthode alloc appelle automatiquement allocWithZone.
    Voilà  ta méthode allocWithZone :

    +(id)allocWithZone:(NSZone *)zone{
    @synchronized(self) {
    if (addressInstance == nil) {
    addressInstance = [super allocWithZone:zone];
    return addressInstance;
    }
    }
    return nil;
    }


    Si addressInstance n'est pas nul, cette méthode renvoie nil, ainsi pour
    [SGLTClass sharedInstance];
    SGLTClass * sgltClass = [[SGLTClass alloc] init];

    la première instruction crée la sharedInstance, donc la deuxième fait que sgltClass=nil.

    Si addressInstance est nul, addressInstance est construit puis renvoyé. Ainsi,
    SGLTClass * sgltClass = [[SGLTClass alloc] init];
    [SGLTClass sharedInstance];

    la première instruction crée la sharedInstance, et l'affecte à  sgltClass, la deuxième l'appelle sans passer par allocWithZone, sans rien faire finalement.

    dans 1223557716:

    En tout cas, je retiens qu'avec les singletons, il ne faut pas utiliser directement l'initialisation classique [[ClassName alloc] init] ; c'est bien ça ?


    [size=12pt]OUI[/size]




  • FloFlo Membre
    00:30 modifié #13
    Je déterre ce sujet parce que je me pose une petite question, comment faire lorsque l'on souhaite instancier un singleton directement dans un fichier XIB ?

    Un peu comme un NSFontManager...

    Si je comprends bien le singleton va être créer par le XIB avec la méthode init et ça va tout craquer non ?
  • Philippe49Philippe49 Membre
    00:30 modifié #14

    NSNib dit :

    During the instantiation process, each object in the archive is unarchived and then initialized using the method befitting its type. View classes are initialized using their initWithFrame: method. Custom objects are initialized using their init method.

    Un singleton est un Custom Object, donc sa méthode init sera appelée. Il faut donc que sa méthode init soit réimplémentée, avec un test pour savoir si la shared instance est déjà  créée.
     
  • FloFlo Membre
    00:30 modifié #15
    Oui mais je croyais que :


    En tout cas, je retiens qu'avec les singletons, il ne faut pas utiliser directement l'initialisation classique [[ClassName alloc] init] ;


  • Philippe49Philippe49 Membre
    juin 2009 modifié #16
    dans 1243808164:

    Oui mais je croyais que :


    En tout cas, je retiens qu'avec les singletons, il ne faut pas utiliser directement l'initialisation classique [[ClassName alloc] init] ;

    A partir du code , cela ne sert à  rien effectivement de faire [[ClassName alloc] init]. Pour le cas que tu poses, on ne va pas réécrire le code de IB, on est donc obligé de se plier au comportement de ce dernier.
  • FloFlo Membre
    00:30 modifié #17
    Ok merci ! 
Connectez-vous ou Inscrivez-vous pour répondre.