Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setting static variables in Objective C

I can't seem to find a way to set the static int I have created to assign unique ids to every object I save to persistent memory. The following gives me a 'no setter method 'setIdGen' for assignment to property.

-(void)viewDidLoad
{
    PlayerMenuController.idGen = [[NSUserDefaults standardUserDefaults] floatForKey:@"idGen"];
}

As well as the above I've tried creating a static setIdGen method that would return bad access errors, and making NSIntegers with their own set methods. My static NSMutableArray gave the same errors when I tried to assign it using = but worked fine when using setArray.

idGen method:

+ (int) idGen
{
    /*static int idGen;
    if(!idGen)
    {
        idGen = 0;
        NSLog(@"idGen reset");
    }*/
    return self.idGen;
}
like image 380
Declan McKenna Avatar asked Apr 12 '13 20:04

Declan McKenna


People also ask

What is static variable in ios?

Static variables are those variables whose values are shared among all the instance or object of a class. When we define any variable as static, it gets attached to a class rather than an object. The memory for the static variable will be allocation during the class loading time.

What does it mean for a variable to be static?

What does static mean? When you declare a variable or a method as static, it belongs to the class, rather than a specific instance. This means that only one instance of a static member exists, even if you create multiple objects of the class, or if you don't create any. It will be shared by all objects.

What is a static variable in Java?

What is Static Variable in Java? Static variable in Java is variable which belongs to the class and initialized only once at the start of the execution. It is a variable which belongs to the class and not to object(instance ). Static variables are initialized only once, at the start of the execution.


3 Answers

Update 2017

Xcode 8 introduced class properties to Objective-C, from the release notes:

Objective-C now supports class properties, which interoperate with Swift type properties. They are declared as @property (class) NSString *someStringProperty;, and are never synthesised.

This means our sample interface below can become:

@interface PlayerMenuController : NSObject

@property (class) int idGen;

@end

However you must still implement the methods yourself, as shown below, as class properties are never synthesised. Note that this also means if you specify property attributes, such as copy, that your methods must implement the semantics.


Original Answer

It looks like you are trying to implement a class property, but there is not such thing in Objective-C - a property is a pair of instance methods.

However, you can fake it...

While the @property declaration is not available to you, if you declare class methods which follow the right naming convention then your compiler may (tested on Xcode 4.6.1, "may" as I cannot offhand point to this being supported, but it's simple to test and will compile time error if not) allow you to use dot notation, i.e. it looks like a class property even if it lacks an @property.

A sample interface:

@interface PlayerMenuController : NSObject

// a class "property"
+ (int) idGen;
+ (void) setIdGen:(int)value;

@end

The implementation:

@implementation PlayerMenuController

static int idGen = 0;

+ (int) idGen { return idGen; }
+ (void) setIdGen:(int)value { idGen = value; }

@end

And test it:

NSLog(@"initial value: %d", PlayerMenuController.idGen);
PlayerMenuController.idGen = 42;
NSLog(@"updated value: %d", PlayerMenuController.idGen);

producing:

initial value: 0
updated value: 42

So we have a "class property" - it looks, walks and quacks like a property ;-)

like image 99
CRD Avatar answered Oct 25 '22 20:10

CRD


If you use a static variable and you ever want to subclass this, the static variable will be the same for both parent and child, so any change when addressing the child class, will also change the same 'property' on it's parent. (and vice versa)

The safe way to do it is using objc/runtime.h associated objects

+(int) idGen
{
    NSNumber* idGen = objc_getAssociatedObject(self, @selector(idGen));

    if (idGen == nil)
    {
        idGen = @0;
    }
    else
    {
        idGen = @([idGen intValue] + 1);
    }

    self.idGen = [idGen intValue];

    return [idGen intValue];
}

+(void)setIdGen:(int)idGen
{
    objc_setAssociatedObject(self, @selector(idGen), @(idGen), OBJC_ASSOCIATION_RETAIN);
}
like image 39
GreatWiz Avatar answered Oct 25 '22 20:10

GreatWiz


You shouldn't be returning self.idGen because an int is not a property. Your code should work if you do this:

 + (int) idGen {
     static int idGen;
     return idGen;
   }
like image 26
Mike Z Avatar answered Oct 25 '22 22:10

Mike Z