40

I want to have a variable that I can access anywhere by importing a header file but I also want it to be static in the sense that there is only one of them created. In my .m file, I specify

static BOOL LogStuff = NO;

and in the initialize method I set the logging value:

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

However I want to be able to access my variable anywhere by importing the .h file so I want to do something like this:

static extern BOOL LogStuff;

but I'm not allowed to do that. Is it possible to do the thing I'm trying to do? Thanks

JPC
  • 8,096
  • 22
  • 77
  • 110

5 Answers5

127

static in Objective-C means a different thing than static in a C++ class, in the context of static class data members and static class methods. In C and Objective-C, a static variable or function at global scope means that that symbol has internal linkage.

Internal linkage means that that symbol is local to the current translation unit, which is the current source file (.c or .m) being compiled and all of the header files that it recursively includes. That symbol cannot be referenced from a different translation unit, and you can have other symbols with internal linkage in other translation units with the same name.

So, if you have a header file declaring a variable as static, each source file that includes that header gets a separate global variable—all references to that variable within one source file will refer to the same variable, but references in different source files will refer to different variables.

If you want to have a single global variable, you can't have it in class scope like in C++. One option is to create a global variable with external linkage: declare the variable with the extern keyword in a header file, and then in one source file, define it at global scope without the extern keyword. Internal linkage and external linkage are mutually exclusive—you cannot have a variable declared as both extern and static.

An alternative, as Panos suggested, would be to use a class method instead of a variable. This keeps the functionality within the scope of the class, which makes more sense semantically, and you can also make it @private if you so desire. It does add a marginal performance penalty, but that's highly unlikely to be the bottleneck in your application (if you suspect it is, always profile first).

Community
  • 1
  • 1
Adam Rosenfield
  • 390,455
  • 97
  • 512
  • 589
  • "then in one source file, define it at global scope without the extern keyword" => What happens if I don't? I am surprised that there is no compiler error out of this. – huggie Dec 08 '13 at 02:30
  • 3
    @huggie: You'll *likely* get a linker error like "symbol(s) not found" or "duplicate symbol". – Adam Rosenfield Dec 09 '13 at 02:56
  • +1 for " Internal linkage and external linkage are mutually exclusive" – onmyway133 Jun 11 '14 at 17:25
  • "all references to that variable within one source file will refer to the same variable, but references in different source files will refer to different variables." I created a project to try and recreate this, but I'm having trouble. I created a header (StaticHeader01.h) that declares a static variable, and two other files (Test01.h|m Test02.h|m) that import StaticHeader01.h and printed out the memory address of the static variable. However, the memory addresses are the same. Can you point out what I'm missing? – Jin Aug 29 '14 at 22:39
  • @AdamRosenfield: Is there any difference in declaring a global const NSString with and without static keyword? If it is global, does keyword static add any value? static NSString *const kSiteURL = @“https://www.google.com”; vs NSString *const kSiteURL = @“https://www.google.com”; – Seema Kadavan Dec 23 '14 at 07:32
6

If LogStuff is a static class field, maybe you can implement static getter and setter?

+ (void)setLogStuff:(BOOL)aLogStuff;
+ (BOOL)logStuff;
Panos
  • 991
  • 4
  • 5
3

Separate global variable (one per source file):

// .h
static NSString * aStatic;

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

Unique global variable:

// .h
extern NSString * anExtern;

// .m
NSString * anExtern = @"global";
SwiftArchitect
  • 47,376
  • 28
  • 140
  • 179
3

Declare it extern BOOL in your header file. Files that #import your header don't know or care if the external symbol is static or not.

NSResponder
  • 16,861
  • 7
  • 32
  • 46
0

I normally use this layout for my statics:

NSMutableArray *macroArray;
BOOL keepMacro;

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

    [macroArray removeAllObjects];
    keepMacro = YES;
}

This is the startMacro command in my application. Both the Bool and the macroArray are static, but notice they are not declared static or extern.

This may not be the best practice, but this is what I do.

Tim Sylvester
  • 22,897
  • 2
  • 80
  • 94
The Lazy Coder
  • 11,560
  • 4
  • 51
  • 69