Objets globaux

tabliertablier Membre
juin 2012 modifié dans API AppKit #1
J'ai des NSArray qui sont utilisés un grand nombre de fois dans de multiples objets. Je cherche un moyen simple de les globaliser. Mes exemples ci-dessous n'en comportent qu'un (ce sont des exemples).



Solution 1

dans un XX.h j'ai écrit: #define truc [NSArray arrayWithObjects:@arg1, @arg2, @arg3, nil]

dans Localise_Prefix.pch j'ai ajouté #import "XX.h

dans le programme j'utilise directement truc et ça marche.

Ce que je trouve idiot: si j'utilise 25 fois truc, 25 truc vont être construits. Comme les arg1, arg2 .... sont des strings constants, je vais avoir simultanément un certain nombre de NSArray identiques dans le POOL.



Solution 2

J'ai créé les NSArray dans un objet (XX) en les déclarants @public. En les accédant par XX->truc dans les autres objets, ça marche mais il faut importer le XX.h dans tout les objets ou dans le Localise_Prefix.pch et la syntaxe est plus longue à  écrire.



Solution 3

J'ai fait un XX.h comme ceci:
#import <Cocoa/Cocoa.h>

NSArray *truc ;

@interface XX : NSObject

{

@public

NSArray *machin ;

}

@end
et un .m comme cela:
#import "XX.h"

@implementation XX

- (void)awakeFromNib

{

machin = [NSArray arrayWithObjects:@arg1, @arg2, @arg3, nil] ; [machin retain] ;

truc = machin ;

}

@end
Je pensais arrivé à  citer le NSArray juste par son nom (truc dans le cas présent). Mais ça ne marche pas.



Y-a-t-il une solution pour créer des "constant-NSArray" qui seront accessibles par un nom unique partout dans le programme et sans les recréer à  chaque utilisation?

Réponses

  • AliGatorAliGator Membre, Modérateur
    juin 2012 modifié #2
    Avec une déclaration dans un .m ou .c et le mot clé extern dans le .h ça marche pas ?


    // Constants.h, inclus un peu partout dans ton code<br />
    // &quot;extern&quot; indique au compilateur que la variable existe et qu&#39;il peut compiler sans soucis s&#39;il la voit, la valeur sera donnée ultérieurement<br />
    extern NSArray* truc;<br />
    <br />
    // Constants.m<br />
    // Et tu ne déclares qu&#39;une seule fois la valeur, dans le .m<br />
    NSArray* truc = [NSArray arrayWithObjects:...];
    
  • hello,



    Je ne sais pas si c'est la bonne démarche mais dans ce cas je stocke les objects dans l'appdelegate et je crée une classe Globals dont le singleton retourne l'objet en passant par l'appdelegate du style :

    [Globals getMonObjet], là  où j'en ai besoin je n'ai qu'à  inclure le Globals.h



    Olivier
  • tabliertablier Membre
    juin 2012 modifié #4
    @Aligator

    Je n'ai pas tout compris sur "extern" alors, j'ai relu le K&R sur le sujet. Le K&R précise que externe doit être placé dans la déclaration interne à  chaque routine. C'est très contraignant (ou alors je suis à  coté du sujet). En Obj-C il doit falloir mettre la déclaration "extern" dans les variables déclarées dans l'interface?

    Pour expliciter exactement ce que je cherche: je voudrais n'avoir qu'une seule déclaration, l'importer dans "Localise_Prefix.pch" et que ce soit suffisant pour que tout les objets du programme connaissent ces variables sans refaire de déclaration dans chaque objet. un peu comme le "common" du Fortran qui définit une zone commune de variable.



    @4le4fclover

    je suis à  peu près incapable de faire ça. Pourquoi n'importes-tu pas le Globals.h dans le Localise_Prefix.pch?

    Aurais-tu un petit exemple (c'est mieux qu'un long discours) pour que je comprenne bien comment cela s'articule?
  • Là  je sèche ...
  • XodiaXodia Membre
    Je vois pas vraiment ce que tu veux dire par "importer dans "Localise_Prefix.pch" ".

    Le concept d'Ali est juste mais peut vite être assez lourd en faisant a chaque coup "extern TYPE var;".



    La solution qui me semble judicieuse pour toi est de faire un Singleton.

    En gros une classe qui va pouvoir être instancier qu'une seule fois, et qui pourra être facilement réutilisable dans divers classe,

    tant que t'appelle [Class getterDeTonArray]; par exemple.



    Par exemple ton Singleton.h pourrait ressembler a :
    <br />
    #import &lt;Foundation/Foundation.h&gt;<br />
    @interface Singleton : NSObject<br />
    {<br />
       NSMutableArray  *_array;<br />
    }<br />
    @property (nonatomic) NSMutableArray *_array;<br />
    +(Singleton *)singleton;<br />
    @end<br />
    




    Puis avoir dans le .m:


    <br />
    @implementation Singleton<br />
    @synthetize _array;<br />
    static Singleton *singleton = nil;<br />
    + (Singleton *) singleton<br />
    {<br />
    	 static dispatch_once_t onceToken;<br />
    	 dispatch_once(&amp;onceToken, ^{<br />
    			   singleton = [[Singleton alloc] init];<br />
    			   [singleton set_array:[NSArray arrayWithObjects: @&quot;un&quot;, @&quot;deux&quot;, nil]];<br />
    	  });<br />
       return singleton;<br />
    }<br />
    // En gros ton pointeur sera charger qu&#39;une seule fois en mémoire<br />
    




    Apres ce qu'il te reste a faire est dans chaque cas ou tu as besoin de l'utiliser, tu importes le .h correspondant

    a la classe et que tu fasses:


    <br />
    [Singleton singleton];<br />
    




    Pour récupérer ton pointeur au même état qu'auparavant.
  • mpergandmpergand Membre
    juin 2012 modifié #7


    Ce que je trouve idiot: si j'utilise 25 fois truc, 25 truc vont être construits. Comme les arg1, arg2 .... sont des strings constants, je vais avoir simultanément un certain nombre de NSArray identiques dans le POOL.




    Si ce sont des chaines constantes, on peut utiliser des tableaux du C:


    <br />
    extern NSString* const Params[];  // dans le .h<br />
    <br />
    NSString* const Params[]={@&quot;arg1&quot;,@&quot;arg2&quot;,@&quot;arg3&quot;};  // quelque part dans un .m<br />
    
  • yoannyoann Membre
    La bonne solution ici est la solution du singleton. C'est ce qu'il faut adopter pour représenter l'accès au modèle de l'application de toute manière.



    Au passage, le code de Xcodia est juste mais j'aurais plus tendance à  placer la déclaration de static Singleton *singleton = nil; à  l'intérieur du scope de la méthode de classe. Il n'y a aucun intérêt à  lui donner une porté globale.
  • tabliertablier Membre
    juin 2012 modifié #9
    Il se trouve que je souhaite leur donner un portée globale, car ces "constant-NSArray" sont utilisés dans une dizaines d'objets et dans plusieurs méthodes dans chaque objet. Comme j'ai 9 de ces "constant-NSArray", ça en fait des appels!!



    Je vais essayer le singleton.
  • Eric P.Eric P. Membre
    juin 2012 modifié #10
    Les extern fonctionnent bien même s'ils représentent le mal absolu pour les puristes.



    Au moins sur iOS... je n'avais pas vu que l'on est dans la rubrique mac.
  • Attention, dans mon commentaire sur la porté globale, je parlais du static Singleton, la variable n'as pas à  être accessible en dehors de la méthode +singleton qui elle permet d'y accéder (principe d'encapsulation).



    J'ai aujourd'hui tendance à  préféré un singleton / sharedinstance d'un objet qui a pour but d'être mon dataProvider dans mes applications. Cela permet d'appliquer un design pattern qui se révélera payant le jour où il faudra faire des modif sur les objets, du KVO, de l'ajout de valeur dynamique, etc.
  • HerveHerve Membre
    juin 2012 modifié #12
    J'ai trouvé ça :


    <br />
    http://fr.wikipedia.org/wiki/Singleton_(patron_de_conception)<br />
    




    Je ne connaissais pas le terme, mais c'est ce que j'aurais essayé de faire devant ce problème.



    (bizarre, si je recopie l'adresse, celle-ci est tronquée et ne fonctionne plus... d'où le fait de la mettre en code, désolé!)
  • AliGatorAliGator Membre, Modérateur
    Autant pointer sur la documentation officielle Apple quitte à  parler de Singleton :

    https://developer.apple.com/library/ios/#documentation/General/Conceptual/DevPedia-CocoaCore/Singleton.html
Connectez-vous ou Inscrivez-vous pour répondre.