web-dev-qa-db-fra.com

Variables publiques, externes, statiques Objective-C

Je veux avoir une variable à laquelle je peux accéder n'importe où en important un fichier d'en-tête mais je veux aussi qu'elle soit statique dans le sens où il n'y en a qu'une créée. Dans mon fichier .m, je précise

static BOOL LogStuff = NO;

et dans la méthode d'initialisation j'ai défini la valeur de journalisation:

+ (void)initialize
{
    LogStuff = ... //whatever
}

Cependant, je veux pouvoir accéder à ma variable n'importe où en important le fichier .h, donc je veux faire quelque chose comme ceci:

static extern BOOL LogStuff;

mais je ne suis pas autorisé à le faire. Est-il possible de faire ce que j'essaie de faire? Merci

38
JPC

static dans Objective-C signifie une chose différente de static dans une classe C++, dans le contexte des membres de données de classe statique et des méthodes de classe statique. En C et Objective-C, une variable ou une fonction static de portée globale signifie que ce symbole a lien interne.

La liaison interne signifie que ce symbole est local à l'unité de traduction, qui est le fichier source actuel (.c Ou .m) En cours de compilation et tous les fichiers d'en-tête qu'il inclut récursivement. Ce symbole ne peut pas être référencé à partir d'une unité de traduction différente et vous pouvez avoir d'autres symboles avec une liaison interne dans d'autres unités de traduction du même nom.

Donc, si vous avez un fichier d'en-tête déclarant une variable comme static, chaque fichier source qui inclut cet en-tête obtient une variable globale séparée - toutes les références à cette variable dans un fichier source fera référence à la même variable, mais les références dans différents fichiers sources feront référence aux variables différentes.

Si vous voulez avoir une seule variable globale, vous ne pouvez pas l'avoir dans la portée de classe comme en C++. Une option consiste à créer une variable globale avec liaison externe: déclarer la variable avec le mot clé extern dans un fichier d'en-tête, puis dans un fichier source, définissez-le à portée globale sans le mot clé extern. La liaison interne et la liaison externe s'excluent mutuellement - vous ne pouvez pas avoir une variable déclarée à la fois extern et static.

Une alternative, comme Panos a suggéré , serait d'utiliser une méthode de classe au lieu d'une variable. Cela maintient la fonctionnalité dans le cadre de la classe, ce qui est plus logique sur le plan sémantique, et vous pouvez également le faire @private Si vous le souhaitez. Cela ajoute une pénalité de performance marginale, mais il est très peu probable que ce soit le goulot d'étranglement dans votre application (si vous pensez que c'est le cas, toujours le profil en premier).

124
Adam Rosenfield

Si LogStuff est un champ de classe statique, vous pouvez peut-être implémenter un getter et un setter statiques?

+ (void)setLogStuff:(BOOL)aLogStuff;
+ (BOOL)logStuff;
4
Panos

Déclarez-le extern BOOL dans votre fichier d'en-tête. Fichiers qui #import votre en-tête ne sait pas ou ne se soucie pas si le symbole externe est statique ou non.

3
NSResponder

Variable globale distincte (une par fichier source):

// .h
static NSString * aStatic;

//.m
static NSString * aStatic = @"separate";

Variable globale unique:

// .h
extern NSString * anExtern;

// .m
NSString * anExtern = @"global";
1
SwiftArchitect

J'utilise normalement cette disposition pour ma statique:

NSMutableArray *macroArray;
BOOL keepMacro;

+ (void) startMacro
{
    if (macroArray == nil)
    {
        macroArray = [[NSMutableArray alloc] initWithCapacity:100];
    }

    [macroArray removeAllObjects];
    keepMacro = YES;
}

Il s'agit de la commande startMacro dans mon application. Bool et macroArray sont statiques, mais notez qu'ils ne sont pas déclarés static ou extern.

Ce n'est peut-être pas la meilleure pratique, mais c'est ce que je fais.

0
The Lazy Coder