47

I am new to Objective C and am reading a book called "Visual Quickstart Guide: Objective-C" by Steven Holzner, Peachpit Press

In Chapter 6: Object Oriented Programming, there is a section called Using Class Variables where he writes:

You can create class variables for use with your classes, but there’s a hitch: every object of that class shares the same variable, so if one object changes a class variable, that variable is changed for all objects. You create class variables with the static keyword. Class variables are often useful: for example, you can use a class variable to keep track of the number of objects of a particular class created in a program. You’ll do that in this task.

And says to enter the following code:

#import <stdio.h>
#import <Foundation/NSObject.h>
@interface TheClass: NSObject
static int count; //error: cannot declare variable inside @interface or @protocol
+(int) getCount;
@end
...

This code gives me an error in Xcode 4:

Cannot declare variable inside @interface or @protocol

Is the book wrong or am I doing something wrong?

Keale
  • 3,924
  • 3
  • 29
  • 46
Rakka Rage
  • 15,941
  • 8
  • 33
  • 45
  • 5
    The book is completely wrong, there is no concept of class variable in Objective-C. You can declare static variables the way one would do in C, but they don't pertain to classes (at least, not semantically). – BoltClock May 17 '11 at 19:10

4 Answers4

101

You declare the static variable in the implementation file (.m file). This should work:

// TheClass.h
@interface TheClass : NSObject
+ (int)count;
@end

// TheClass.m
static int theCount = 0;

@implementation TheClass
+ (int) count { return theCount; }
@end

It's not a class variable per se; Objective-C has no notion of a class variable. However, coupled with the class method for retrieving this variable, it functions similarly to a class variable. However, it's really just a C static variable that's accessible by the class's implementation.

mipadi
  • 398,885
  • 90
  • 523
  • 479
  • 11
    What if the "class variable" is an object (say NSSet), which requires some initialization? – Uri London Aug 04 '12 at 16:57
  • @mipadi - Please clarify for me. I'm not sure of the definition of a "class variable" and therefore not sure I understand why "it's not a class variable." A static variable declared in the implementation file is shared by all instances of the class and only accessible by instances of that class. Is it not a "class variable" because it is not accessible by subclasses? Or is there some other reason you are making the distinction? I'd sincerely like to learn. – Chuck Krutsinger Oct 12 '13 at 19:18
  • 1
    @Chuck-Krutsinger As no one else has answered: The concept of a class variable is the same as a class method (but a variable) i.e. a variable which can be accessed without creating an instance of a class, which is exactly what a static variable in the implementation would do. The reason he uses the term 'class variable' is because that is what the question was about, but they don't exist because static already provides the necessary functionality. – Simon Jackson Feb 25 '14 at 13:37
  • Use ''+ (void)initialize'' for the class (the analogue of a static constructor in Java or C#) – Julian Gold Apr 10 '14 at 12:15
  • Hey I made a gist some time ago, not ARC compatible but it can actually be used in ARC by using the assign methods and specifying strong or weak references. https://gist.github.com/darionco/03649feeee57f86fee3f – Dario Sep 05 '14 at 03:33
15

I’ve seen one Visual Quickstart Guide about Unix and it sucked big time. This one does not seem to be much better, at least from the sample. The correct way to create a class variable in Objective-C looks like this:

// Counted.h
@interface Counted : NSObject

+ (NSUInteger) numberOfInstances;

@end

// Counted.m
#import "Counted.h"

static NSUInteger instances = 0;

@implementation Counted

- (id) init {
    …
    instances++;
    …
}

- (void) dealloc {
    instances--;
}

+ (NSUInteger) numberOfInstances {
    return instances;
}

@end

This is in fact a static variable, not a true class variable. But you should not worry about class variables too much anyway, they’re usually a sign that you’re doing something wrong. (I’m oversimplifying a bit, but not much.)

If you’re looking for a decent Objective-C book, read the one by Apple. It’s free and it’s a good reading.

zoul
  • 102,279
  • 44
  • 260
  • 354
11

If the "class variable" needs more than trivial initialization, use dispatch_once:

@interface Foo ()
+ (Foo *)singleton;
@end

+ (Foo *)singleton {
    static Foo *_singleton;
    static dispatch_once_t oncePredicate;

    dispatch_once(&oncePredicate, ^{
        _singleton = [[Foo alloc] init];
    });

    return _singleton;
}
ctd
  • 111
  • 1
  • 5
6

You should declare the variable in the .m file, where the @implementation is put. So,

#import "TheClass.h"

static int count;

@implementation

...

@end

It is important to note that Objective-C does not actually support class variables. But you can simulate them with static variables, as we are doing here.

EJV
  • 1,009
  • 1
  • 10
  • 17