3

I want to have a static variable in Cocoa.

After looking at How do I declare class-level properties in Objective-C?, I am unclear whether there is anything wrong with what I have always done so far, i.e.

// Foo.m
static NSString* id;
@interface Foo ()

instead of

// Foo.h
@interface Foo {
}

+(NSString*) id;

// Foo.m
+(NSString*) id
{
  static NSString* fooId = nil;

  if (fooId == nil)
  {
    // create id
  }

  return fooId;
}

Obviously, the second approach offers an opportunity for initializing the id. But if I initialize the id myself somewhere else in the code, within, say a getter:

-(NSString*) getId
{
    if (id==nil) {
      id =  ... // init goes here
    }
    return id;
}

Then is there anything wrong with the simple static declaration approach as opposed to the more complex class function approach? What am I missing?

Community
  • 1
  • 1
Lolo
  • 3,935
  • 5
  • 40
  • 50

1 Answers1

7

First, what you are asking for is a global variable, a static is similar but a little bit different...

Putting a static declaration outside of any @interface in a header (.h) file will create a different variable in each implementation (.m) file you include the header in - not what you want in this case.

So static on a declaration creates a variable whose lifetime is that of the whole application execution but which is only visible within the compilation unit (e.g. the implementation file) in which it appears - either directly or via inclusion.

To create a global variable visible everywhere you need to use extern in the header:

extern NSString *id;

and in your implementation repeat the declaration without the extern:

NSString *id;

As to what is wrong with global variable vs. class methods, that is a question on program design and maintainability. Here are just a few points to consider:

  • With a method the value cannot be changed unless you provide a setter method as well as getter method. Variables are always read-write.
  • Namespace pollution: a class method is only valid when paired with its class name ([YourClass id]); the variable name is valid everywhere it's included simply as id; that both pollutes the name space and loses the connection between id and YourClass - which leads us to...
  • Encapsulation: globals variables break strong encapsulation, and encapsulation aids program design and maintenance - this is a big topic.

That said, there can be a time and a place for globals, sometimes...

After question updated

A static variable declared in the implementation is effectively a "class variable" - a variable shared by all instances of the class.

The pros'n'cons of a class variable vs. setter & getter class methods are exactly the same as the pros'n'cons of an instance variable vs. properties & setter/getter instance methods.

Class setters/getters allow for validation and other logic to be executed on each read/write; and localization of memory management - in short the abstraction and encapsulation benefits of any method.

Therefore whether you use a variable or a setter/getter depends on your application. It is the same question as whether you use an instance variable or setter/getter/property.

CRD
  • 52,522
  • 5
  • 70
  • 86
  • But you can't provide both getter and setter methods operating on a method-level static variable; the two methods could each have static variables with the same name, but they would be distinct things. – echristopherson Oct 05 '12 at 21:04
  • If you use a compilation unit-level static variable in a class interface file, isn't it certain that the static variable used by class methods will always be the same variable, while the implementation files that #import that class's interface file actually set up static variables which have the same name but are distinct? It seems that should be true, since the class implementation is presumably compiled separately from other implementations that import its interface; but I'd like to know for sure. – echristopherson Oct 05 '12 at 21:12
  • @echristopherson - correct, method-level static variables are limited in visibility to the method in which they are declared. Variable-based class-level setter and/or getter methods would operate on a class-level static variable. Any static variable declared in the implementation file outside of any method or function is a class-level static variable - the equivalent of a "class variable" in some other languages. A logical place to place such declaration *within* the `@implementation` block (and outside everything else in that block) to make it visually clear they belong to the class. – CRD Oct 05 '12 at 22:50
  • @echristopherson - re: compilation unit-level static variables in header files - yes a *distinct* variable is created in every compilation unit the header is included in. Static variable declarations in header files are rather obscure and you will (or should!) rarely come across them. – CRD Oct 05 '12 at 22:56
  • First, my apologies. I DID mean static variables and meant to show the static allocated in the m file, not in the h file like my comment suggested. I am correcting my original post. I understand the downside of globals and am solely interested in the difference of the two approaches I have in my post. – Lolo Oct 09 '12 at 15:32