Constante associée à une classe, via une catégorie
colas_
Membre
Bonsoir,
suivant les conseils donnés ici par certains, j'essaie de limiter l'usage des "variables" de classe.
Néanmoins, pour des raisons d'optimisation prématurée :P, je voulais avoir votre avis sur cet extrait de code :
@interface NSDate(MyCategory)
- (NSString *)frenchPrint;
@end
@implementation NSDate(MyCategory)
static NSLocale * frenchLocale ;
- (NSString *)frenchPrint
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
frenchLocale = [[NSLocale alloc] initWithLocaleIdentifier:@fr_FR];
});
NSDateFormatter *formatterForTheDay = [[NSDateFormatter alloc] init];
formatterForTheDay.locale = frenchLocale;
//etc.
}
@end
Est-ce ok ?
En particulier, si dans une autre catégorie au-dessus de NSDate, j'ai aussi
static NSLocale * frenchLocale ;
est-ce ok ?
Merci
PS : j'ai déjà une idée pour améliorer ce code
static NSLocale * _frenchLocale ;
- (NSLocale *)frenchLocale_MyCategory
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_frenchLocale = [[NSLocale alloc] initWithLocaleIdentifier:@fr_FR];
});
return _frenchLocale;
}
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Hello,
Je crois que c'est plutôt le formater qu'il faut éviter de créer plusieurs fois et non pas NSLocale.
La deuxième question je ne l'ai pas trop saisie. static pour une variable globale veut dire que cette ladite variable est accessible par toute méthode/fonction dans le même fichier source que cette variable.
ça restera quand même dangereux car une variable "semi-globale" on va dire, puisque n'importe quel code dans le fichier pourra y accéder sans protection en particulier sans thread-safety.
Et surtout cette variable globale n'est pas liée à une instance mais partagée par toutes les instances (ça c'est le but du static et c'est sans doute voulu dans ton cas ceci dit)
Il serait bien mieux de mettre cette variable "static" non pas au niveau racine du fichier mais plutôt à l'intérieur de la méthode frenchPrint. Exactement sur le même modèle que tu as fait pour le "dispatch_once_t onceToken" en fait.
Comme ça la variable n'est accessible que depuis l'intérieur de cette méthode, et invisible de l'extérieur de cette méthode, que ce soit dans les autres méthodes de cette catégorie où d'une autre catégorie ou de la classe en question, donc pas de risque de conflit.
Après je confirme ce que dit samir ce qui prend le plus de temps à initialiser et qu'il faut donc mettre en cache pour l'initialiser qu'une fois pour toutes c'est plutôt le NSDateFormatter que la NSLocale qui elle ne coûte pas grand chose à initialiser.
Donc en fait prendre le code de samir MAIS mettre le "static NSDateFormatter" à l'intérieur de ta méthode de la même manière que tu as fait pour le onceToken.
Merci Samir.
Quand on parle de fichier source, il s'agit vraiment du même fichier ? Je crois que je suis le prototype de futur adepte de Swift, car j'ai appris l'objective-C sans connaà®tre le C et je trimballe des faiblesses !
Toutes mes catégories sont dans des fichiers séparés et je voudrais utiliser ce même procédé dans plusieurs catégories. Donc, je voulais savoir si avec des static avec le même nom était ok.
D'après ce que tu dis, c'est ok, n'est-ce pas ?
De quel conflit parles-tu ?
En effet, je n'écris cette variable que dans le dispatch_once.
J'aurai bien ajouté un `const` mais le compilo ne veut pas.
En fait, il se peut que j'utilise le NSLocale (ou le NSCalendar) depuis plusieurs méthodes.
@Ali
J'ai l'impression que tu te contredis car d'un côté tu dis que la variable ne sera accessible que depuis le fichier et de l'autre tu dis qu'il faut la protéger pour qu'elle ne soit pas vue par la classe ou par d'autres catégories. Erreur de ta part ?
Je vais faire la même chose pour NSFormatter.
En gros, j'affiche des dates dans une table view...
Alors :
- peut-être que c'est ce que tu veux, d'avoir des variables qui ont le même nom mais qui en fait sont 2 variables totalement différentes entre les deux fichiers, mais franchement je te le déconseille, car c'est des coups à confondre tout et à plus savoir de quelle variable on parle (sympa pour débuguer aussi...), donc dans ce cas préfère utiliser explicitement des noms différents, ça t'évitera des incompréhensions plus tard quand tu te reliras ou devra débuguer
- ou alors si tu veux que ça représente en fait la même variable (le même emplacement mémoire, etc, donc si tu changes la valeur depuis un fichier ce changement soit aussi visible dans l'autre fichier), alors ce n'est pas une variable "static" qu'il te faut. A la limite c'est plutôt avec "extern" que tu vas devoir jouer (je vais expliquer ça dans un post séparé)
Dans ce cas, fais-en une méthode dans ta classe. Surtout si c'est une constante lady-initialisée lors de son premier accès, ça conviendrait bien mieux. Et tu peux faire pareil pour ton NSDateFormatter. Du style : Comme toute variable déclarée à l'intérieur d'un block entre accolades, tes variables frLocale et formatterForTheDay ne seront visible/accessible que dans ce block entre accolades, donc ici ne seront visible qu'à l'intérieur du code de la fonction en question.
Par contre elles utilisent le mot clé "static" qui, utilisé dans ce contexte (= à l'intérieur d'une fonction, et pas au niveau du fichier) signifie que la variable gardera sa valeur entre chaque appel à la fonction, et sera en fait globale, non pas au sens "accessible globalement" mais au sens "partagé par toutes les instances de ta classe, car ne sera pas lié à ta classe et à ton instance comme peut l'être une @property, mais va continuer à garder sa valeur pendant toute la vie de l'application donc y compris entre plusieurs appels à cette méthode.
Non non, je ne me contredis pas.
Si tu utilises une "static" au niveau du fichier, elle sera accessible que depuis le fichier. Ca ne l'empêche pas d'être vue par d'autres classes ou catégories... qui seraient déclarées dans le même fichier. J'ai bien dit:
Je faisais référence à
Sinon, il faut faire attention avec tes méthode de classe encapsulant les static car si je crée la même méthode de classe dans une autre catégorie, je risque d'avoir des problèmes.
D'où plutôt le code :
Sinon, autre lien intéressant sur la NSCalendar
http://mikeabdullah.net/NSCalendar_currentCalendar.html
Note qu'il y a une différence de signification entre le cas où tu utilises "static" à la racine d'un fichier et quand tu l'utilises pour déclarer une variable à l'intérieur d'un block entre accolades (notamment à l'intérieur d'une fonction donc)
- "static" utilisé pour une déclaration à la racine d'un fichier veux dire "cette variable n'est visible / accessible que depuis le fichier. Par contre n'importe qui dans le fichier pourra y avoir accès, dans ce sens elle est "globale" car "partagée par tous les trucs déclarés dans le même fichier (y compris par toutes les classes ou catégories que tu mettrais dans ce fichier si jamais tu faisais le choix bizarre de mettre plusieurs classes ou catégories dans un même gros fichier alors que la tendance est plutôt, comme tu le fais, de les mettre dans des fichiers séparés).
Du coup dans ce contexte le mot clé "static" sert plutôt pour dire "je restreint l'accès et la visibilité de cette variable uniquement à ce fichier, et pas aux autres fichiers".
- "static" utilisé à l'intérieur d'un bloc entre accolades, genre dans une fonction, veut plutôt dire "cette variable aura un état global partagé par tout les appels à cette fonction. Elle gardera sa valeur même entre 2 appels à cette fonction.
Le fait que cette variable ne soit accessible que par le code à l'intérieur de la même fonction n'est du coup pas trop lié au fait qu'elle soit déclarée "static", puisque ça c'est déjà le cas de n'importe quelle variable déclarée dans le corps d'une fonction, elle n'est accessible/visible que par le code dans le même bloc d'accolades.
Du coup dans ce contexte le "static" sert plutôt pour dire "en plus d'être comme les autres variables déclarées dans un bloc entre accolades qui ne sont pas visibles à l'extérieur de ces accolades, je marque cette variable colle "static" pour dire qu'elle doit continuer à vivre même quand on sort de la fonction, et ainsi quand on re-rentrera dans la fonction on retrouvera la valeur qu'elle avait la dernière fois.
Du coup, ce mot clé "static" est souvent difficile à appréhender car il n'a pas la même signification/interprétation en pratique selon s'il est utilisé pour une déclaration "top-level" (à la racine du fichier) ou une déclaration à l'intérieur d'une fonction... (et du coup y'a de quoi se mélanger les pinceaux). Même mot clé dans les 2 cas, mais deux cas d'usage pourtant bien différents...
Certes, mais je ne comprend pas trop le rapport avec l'usage des static ou pas ?!
Si tu implémentes 2 fois la même méthode dans 2 catégories différentes d'une même classe, ou même que tu implémentes dans une catégorie une méthode qui est déjà implémentée dans une classe, de toute façon tu vas avoir des problèmes, car tu auras 2 implémentations différentes pour une même méthode.
Je voudrais juste rajouter une chose : A chaque fois qu'on veut créer une seule instance (comme l'exemple de @colas) on pense directement au dispatch_one alors que dans la majorité des cas on en a pas besoin et une simple variable static suffit.
Utiliser dispatch_one si concurrence éventuelle de plusieurs threads
sinon une simple variable static. ( un test == nil)