Java Developer’s Guide to Static variables in Objective-C

The concepts of “static” variables are different in Objective-C compared to Java. That does not mean, however, that the concepts do not exist.

Consider the following common uses of ‘static’ in Java:

  • public static final int MY_CONSTANT = 0; // Constant
  • public static String MyVar = “Foo”; // Class Variable

In all of the above cases, the use of the keyword ‘static’ is used to consistently refer to a variable that is class scoped and not instance scoped. In the case of a static variable, this means that multiple instances of the same class would all share the state for the variable; Change the variable and it changes for all instances of that class.

Let’s take each of these cases and examine how they translate into Objective-C constructs …

Example: Using ‘static’ to define Constants

I often find myself using public static final qualifiers to define constants that are used throughout my code. A common declaration looks something like this :

public class MyClass {
  public static final int MY_CONSTANT = 0;

… and its usage would look something like this:

int i = MyClass.MY_CONSTANT;

There is no direct equivalent of this in Objective-C, but I do find that the use of #define will often provide an acceptable alternative. The following is how you would declare a constant using #define:

#define MY_CONSTANT 0

… and its usage in Objective-C would look something like this:

int i = MY_CONSTANT;

NOTE: Constructs like #define are called ‘macros’ in Objective-C and have many uses with no equivalent in Java. They are very powerful and can be used to do some fancy conditional include/exclude of entire code blocks. I’d strongly recommend that you take a closer look at ‘macros’ in Objective-C to learn more.

Example: Using ‘static’ to Define Class Variables

Oddly enough, I found it very difficult to find out how to define a static variable in Objective-C. I suspect that must mean that its use may be discouraged for some reason by the creators of Objective-C. Personally I see no issue with them as long as they are used safely. Obviously, race conditions and other common threading problems often result from the use of static variables but that can be easily avoided with careful use of synchronization and semaphores.

All that said, here is how you define a static variable in Objective-C:

@interface MyClass 
  // ...
+ (NSString *)myVar;
+ (void)setMyVar:(NSString *)newVa;
@implementation MyClass
static NSString *myVar;
+ (NSString *)myVar { return myVar; }
+ (void)setMyVar:(NSString *)newVar { myVar = newVar; }

NOTE: Just because the keyword ‘static’ is used, it doesn’t mean the same thing as it does in Java. In the above example, the static variable ‘myVar’ is only visible to code in the *.m file so if you want to access the value externally, you will need to add static accessors (e.g. Class scoped methods declared with ‘+’ instead of ‘-‘).

UPDATE: Another reader has pointed out that extern syntax in C can be used to expose a variable to anyone that imports the header file that defines it. However, extern is not an alternative to a class-scoped static variable in Java, in fact it is more like a global variable … so use with caution. The process outlined in this blog post of wrapping a static C style variable with Objective-C style class-methods is the closest equivalent you will find for a Java static variable.

  1. The use of #define (ie, C preprocessor macros) is powerful, but very easy to abuse/misuse. The use of #define for constants is probably one of the safest uses of it, but when you take it further it is very easy to introduce side effects. Consider this:

    #define MULT(a, b) a * b

    Which on the face of it is a simple macro that will return the product of two numbers. Then, consider this use of the macro:

    int x = 2;
    int y = MULT(x, x + 1);

    You might expect y to be 6 when this runs, but actually you’ll get 5 because the macro expands to:

    int y = x * x + 1;

    This is pretty standard stuff, but it is something I can see Java coders tripping up over. It is important to realize that the preprocessor is just dealing with text, and the compiler gets what the preprocessor spits out, which in this case is not what you would expect.

    On the topic of constants, there are at least a couple of other ways to define them. On a global basis you can use tyepdef enum, in a header file, to define constants that are available outside of your Obj-C class. So for example in your .h file, before your interface definition, you could put:

    // Graphics.h

    typedef enum {
    DOTTED = 1,
    SOLID = 0,
    } GraphicsStyle;

    Now, any file that #imports Graphics.h can do:

    GraphicsStyle gs = DOTTED;

    In this case, gs is a variable of the enum type GraphicsStyle, and so you can do things like:

    if (gs == DOTTED) {

    And so on. enums can be assigned to ints and vice versa, but there are some safety issues to consider. Google “C enums” for more info! One thing to note is that enums are not namespaced by the typedef, so this will give a duplicate symbol warning on VALUE:

    typedef enum {
    VALUE = 1,
    } SomeValues;

    typedef enum {
    VALUE = 1,
    } SomeOtherValues;

    This is why you’ll see the following used in Obj-C:

    typedef enum {
    } UIStatusBarStyle;

    One other thing to note here is that enums are auto-incrementing, and the first value in the enum is set to 0 by default. Hence, in the UIStatusBarStyle enum above, UIStatusBarStyleGray will have value 0, and each succeeding enum element will have a value incremented by 1.

    Hopefully all the above info is correct, insert usual disclaimers, etc. I’m much more familiar with C++ and like Rodney I’m finding my way w/Obj-C albeit coming from a different angle.

  2. Thanks for the helpful article. I am wondering how and when myVar gets released in your example.

  3. @Cookiecat: It won’t. But you wouldn’t want that anyway since it is a static variable and thus has a lifetime over the whole process. If you do know that you need the variable only to some specific point, you can always release it manually.

    Perphaps an addition to the above example: If you want to have a default value for your variable you can override the + (void) initialize; or + (void) load; method (Refer to the documentation of NSObject to know which one to use when), which are called before the class is used.

Comments are closed.