229

Maybe this is obvious, but I don't know how to declare class properties in Objective-C.

I need to cache per-class a dictionary and wonder how put it in the class.

Jim Puls
  • 79,175
  • 10
  • 73
  • 78
mamcx
  • 15,916
  • 26
  • 101
  • 189

10 Answers10

204

properties have a specific meaning in Objective-C, but I think you mean something that's equivalent to a static variable? E.g. only one instance for all types of Foo?

To declare class functions in Objective-C you use the + prefix instead of - so your implementation would look something like:

// Foo.h
@interface Foo {
}

+ (NSDictionary *)dictionary;

// Foo.m
+ (NSDictionary *)dictionary {
  static NSDictionary *fooDict = nil;
  if (fooDict == nil) {
    // create dict
  }
  return fooDict;
}
Andrew Grant
  • 58,260
  • 22
  • 130
  • 143
  • 1
    Any idea why this could cause a BAD ACCES exception? I'm loading in a UITableView and the first batch load fine but in scrolling get BADACCES. – mamcx Mar 30 '09 at 15:17
  • You would have to paste your code. It's important to remember that by default UITableView reuses cells when scrolling if they have the same identifier. – Andrew Grant Mar 30 '09 at 15:55
  • 23
    Is this right? Won't setting fooDict to nil as the first line of the dictionary method always result in the dictionary being recreated each time? – PapillonUK Apr 06 '12 at 22:02
  • 4
    http://stackoverflow.com/questions/554969/using-static-keyword-in-objective-c-when-defining-a-cached-variable – Undistraction May 08 '12 at 19:42
  • 62
    The line static NSDictionary *fooDict = nil; will only get executed once! Even in a method called multiple times, the declaration (and also in this example the initialisation) with the keyword static will be ignored if a static variable exists with this name. – Binarian Aug 14 '13 at 17:09
  • Can this be called with `Foo.dictionary`? – Ky - Apr 08 '15 at 15:33
  • 3
    @BenC.R.Leggiero Yes, absolutely.  The `.`-accessor syntax isn't tied to properties in Objective-C, it's just a compiled-in shortcut for any method that returns something without taking any args.  In this case I would prefer it— I personally prefer `.` syntax for any usage where the client code intends to get something, not perform an action _(even if the implementation code may create something once, or perform side-effect actions)_.  Heavy usage `.` syntax also results in more-readable code: presence of `[…]`s mean something significant is being done when fetches use `.` syntax instead. – Slipp D. Thompson May 06 '15 at 00:06
  • 4
    Have a look at Alex Nolasco's answer, class properties are available since the Xcode 8 release : http://stackoverflow.com/a/37849467/6666611 – n3wbie Feb 08 '17 at 11:13
  • Does this mean that fooDict would be a property of a class's (in this case static) method? – Vladimir Despotovic Sep 22 '17 at 21:13
  • @AndrewGrant Isn't it more simple to just do static NSDictionary *fooDict = nil; instead of all that code? – Vladimir Despotovic Sep 22 '17 at 21:22
121

I'm using this solution:

@interface Model
+ (int) value;
+ (void) setValue:(int)val;
@end

@implementation Model
static int value;
+ (int) value
{ @synchronized(self) { return value; } }
+ (void) setValue:(int)val
{ @synchronized(self) { value = val; } }
@end

And i found it extremely useful as a replacement of Singleton pattern.

To use it, simply access your data with dot notation:

Model.value = 1;
NSLog(@"%d = value", Model.value);
spooki
  • 1,211
  • 1
  • 8
  • 3
  • 3
    That is really cool. But what on earth does `self` mean inside a class method? – Todd Lehman Apr 11 '13 at 05:45
  • 8
    @ToddLehman `self` is [the object that's received the message](https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/WorkingwithObjects/WorkingwithObjects.html#//apple_ref/doc/uid/TP40011210-CH4-SW5). And since [classes are also objects](https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/DefiningClasses/DefiningClasses.html#//apple_ref/doc/uid/TP40011210-CH3-SW18), in this case `self` means `Model` – spooki Apr 15 '13 at 17:31
  • 6
    Why would the getter need to be `@synchronized`? – Matt Kantor Jan 31 '14 at 00:57
  • 1
    This is actually pretty cool that this works. That you can wright your own class level properties that work exactly like the real thing. I guess synchronising self is the equivalent of using 'atomic' in your property declaration and can be omitted if you want the 'nonatomic' version? Also i would consider naming the backing variables with '_' as is default by apple and also improves readability since returning/setting self.value from the getter/setter causes infinite recursion. In my opinion this is the right answer. – Peter Segerblom May 02 '14 at 12:14
  • 3
    It's cool, but... 10 lines of code just to create 1 static member? what a hack. Apple should just make this a feature. – John Henckel Jul 15 '14 at 14:31
  • It's INCREDIBLE that this works. I just read about Apple's implementation of "universal" dot notation though, and the rest of that package is just evil! – Dev Kanchen Aug 25 '14 at 03:58
  • 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:31
  • 1
    based on my experience, setValue will not work from inside a block. When in a block, all static variables are considered const. When execution exits block, the value is reverted. No warning nothing. And you can't have __block static variables. BE CAREFUL!!! – Radu Simionescu May 23 '16 at 09:33
  • 1
    @JohnHenckel well, I suppose now you already know that it's very easy to add static member variable to Swift. :D – Chen Li Yong Nov 02 '16 at 08:40
118

As seen on WWDC 2016/XCode 8 (what's new in LLVM session @5:05). Class properties can be declared as follows

@interface MyType : NSObject
@property (class) NSString *someString;
@end

NSLog(@"format string %@", MyType.someString);

Note that class properties are never synthesized

@implementation
static NSString * _someString;
+ (NSString *)someString { return _someString; }
+ (void)setSomeString:(NSString *)newString { _someString = newString; }
@end
Alex Nolasco
  • 18,750
  • 9
  • 86
  • 81
  • 9
    It should perhaps be made explicit that this is _only_ sugar for the accessor declarations. As you noted, the property is not synthesized: a (`static`) variable must still be declared and used, and the methods implemented explicitly, just as it they were previously. Dot syntax already worked previously, too. In all, this sounds like a bigger deal than it really is. – jscs Jun 20 '16 at 02:27
  • 8
    The big deal is this means that you can access singletons from Swift code without using (), and the type suffix is removed by convention. E.g. XYZMyClass.shared (Swift 3) instead of XYZMyClass.sharedMyClass() – Ryan Oct 12 '16 at 04:02
  • 1
    This doesn't look thread safe. If this could be mutated from different threads in your code I would make sure you handle the potential race condition this would create. – SmileBot May 06 '17 at 13:55
  • A nice clean interface for consuming classes but it's still a ton of work. Tried this with a static block and it wasn't much fun. In fact just using the static was much easier. – Lucas van Dongen Dec 05 '17 at 23:26
  • 1
    the implementation can be easily enhanced for thread-safe "singleton" behaviour, using dispatch_once token - but otherwise the solution correctly demonstrates the answer – Motti Shneor Jan 28 '19 at 07:15
  • OP didn't ask for singleton, but for a class property (e.g. NSWindow class maintains a list of all NSWindow instances - the list you see in your "Window" menu in any Mac application.) To make this implementation thread-safe, simply embed the code within each accessor in a `@synchronized(self) { };` scope. – Motti Shneor Feb 15 '22 at 09:15
63

If you're looking for the class-level equivalent of @property, then the answer is "there's no such thing". But remember, @property is only syntactic sugar, anyway; it just creates appropriately-named object methods.

You want to create class methods that access static variables which, as others have said, have only a slightly different syntax.

Jim Puls
  • 79,175
  • 10
  • 73
  • 78
  • Even thought properties are syntactic It would still be nice to be able to use the dot syntax for stuff like MyClass.class instead of [MyClass class]. – Zaky German Oct 16 '12 at 08:51
  • 5
    @ZakyGerman You can! `UIDevice.currentDevice.identifierForVendor` works for me. – tc. Nov 09 '12 at 13:57
  • 1
    @tc. Thank you! Filling silly now. For some reason, I was convinced that I tried that in the past but it didn't work. Is that a new feature by any chance? – Zaky German Nov 10 '12 at 22:01
  • 1
    @ZakyGerman It has worked for at least a year or two for class methods. I believe it has always worked for instance methods if the getter/setter methods have the expected types. – tc. Nov 13 '12 at 20:17
24

Here's a thread safe way of doing it:

// Foo.h
@interface Foo {
}

+(NSDictionary*) dictionary;

// Foo.m
+(NSDictionary*) dictionary
{
  static NSDictionary* fooDict = nil;

  static dispatch_once_t oncePredicate;

  dispatch_once(&oncePredicate, ^{
        // create dict
    });

  return fooDict;
}

These edits ensure that fooDict is only created once.

From Apple documentation: "dispatch_once - Executes a block object once and only once for the lifetime of an application."

Quentin
  • 3,971
  • 2
  • 26
  • 29
  • 3
    Isn't the dispatch_once code irrelevant since a static NSDictionary could be initialized on the first line of +(NSDictionary*) dictionary method and since it's static it will only be initialized once anyways? – jcpennypincher Oct 22 '13 at 20:29
  • @jcpennypincher Attempting to initialize the dictionary on the same line as its static declaration yields the following compiler error: `Initializer element is not a compile-time constant`. – George WS Oct 23 '13 at 20:45
  • @GeorgeWS You're only getting that error because you're attempting to initialize it to the result of a function (alloc and init are functions). If you initialize it to nil, and then add the if(obj==nil) and initialize in there, you'll be fine. – Rob Mar 26 '14 at 19:58
  • 2
    Rob, that isn't thread safe. The code presented here is best. – Ian Ollmann May 27 '15 at 22:14
  • I like this answer best, because it is complete and thread safe - however, it only deals better with the implementation, while the op's question was about the declaration of class properties - not their implementation (which has nothing to do with the implementation). Thanks anyway. – Motti Shneor Jan 28 '19 at 07:17
16

As of Xcode 8 Objective-C now supports class properties:

@interface MyClass : NSObject
@property (class, nonatomic, assign, readonly) NSUUID* identifier;
@end

Since class properties are never synthesised you need to write your own implementation.

@implementation MyClass
static NSUUID*_identifier = nil;

+ (NSUUID *)identifier {
  if (_identifier == nil) {
    _identifier = [[NSUUID alloc] init];
  }
  return _identifier;
}
@end

You access the class properties using normal dot syntax on the class name:

MyClass.identifier;
berbie
  • 978
  • 10
  • 13
7

Starting from Xcode 8, you can use the class property attribute as answered by Berbie.

However, in the implementation, you need to define both class getter and setter for the class property using a static variable in lieu of an iVar.

Sample.h

@interface Sample: NSObject
@property (class, retain) Sample *sharedSample;
@end

Sample.m

@implementation Sample
static Sample *_sharedSample;
+ ( Sample *)sharedSample {
   if (_sharedSample==nil) {
      [Sample setSharedSample:_sharedSample];
   }
   return _sharedSample;
}

+ (void)setSharedSample:(Sample *)sample {
   _sharedSample = [[Sample alloc]init];
}
@end
Jean-Marie D.
  • 81
  • 2
  • 5
7

Properties have values only in objects, not classes.

If you need to store something for all objects of a class, you have to use a global variable. You can hide it by declaring it static in the implementation file.

You may also consider using specific relations between your objects: you attribute a role of master to a specific object of your class and link others objects to this master. The master will hold the dictionary as a simple property. I think of a tree like the one used for the view hierarchy in Cocoa applications.

Another option is to create an object of a dedicated class that is composed of both your 'class' dictionary and a set of all the objects related to this dictionary. This is something like NSAutoreleasePool in Cocoa.

mouviciel
  • 66,855
  • 13
  • 106
  • 140
3

If you have many class level properties then a singleton pattern might be in order. Something like this:

// Foo.h
@interface Foo

+ (Foo *)singleton;

@property 1 ...
@property 2 ...
@property 3 ...

@end

And

// Foo.m

#import "Foo.h"

@implementation Foo

static Foo *_singleton = nil;

+ (Foo *)singleton {
    if (_singleton == nil) _singleton = [[Foo alloc] init];

    return _singleton;
}

@synthesize property1;
@synthesize property2;
@synthesise property3;

@end

Now access your class-level properties like this:

[Foo singleton].property1 = value;
value = [Foo singleton].property2;
Pedro Borges
  • 1,568
  • 1
  • 14
  • 25
-4

[Try this solution it's simple] You can create a static variable in a Swift class then call it from any Objective-C class.

jawad
  • 775
  • 6
  • 16