Objective-C Class Initialization

A template for shared resources

2019

Class variables are incredibly useful for constants and other expensive objects. Getting them initialized with objects can be a little more complicated.

Variable Placement

Static variables intended to be used by a class need to be accessable by that class. To allow for this I like to define them above @implementation and after the @interface extension. To follow convention they should also be prefixed with a lowercase k.

Examples will be based around a date formatter. This is commonly done as NSDateFormatter is expensive to produce.

SomeClass.m
@interface SomeClass ()
@end

static NSDateFormatter *kDateFormatter;

@implementation SomeClass
@end

The +initialize Method

The +initialize method is called before any instances of a class are created. While they shouldn’t be called more then once per class they are. If a subclass fails to create its own +initialize method its parents is called. Traditionally a check is preformed for the class type to guard against this.

if ( self == [SomeClass class] )

While this guards against the previously mentioned issue its not foolproof. Suppose somebody calls +initialize by mistake. This would pass the check and a second instance would be created without release the previous instance. This can theoretically be run more then once if its called on the same class which could cause leaks and perform unnecessary work. The modern approach is to use dispatch_once() which will only ever be called once. As the token doesn’t need to be accessable outside of the method its placed in the +initialize method.

+ (void)initialize
{
	static dispatch_once_t onceToken;
	dispatch_once(&onceToken, ^{
		kDateFormatter = [[NSDateFormatter alloc] init];
		[kDateFormatter setDateFormat:@"EEE, dd MMM yyyy HH:mm:ss ZZ"];
	});
}

Putting It All Together

SomeClass.h
@interface SomeClass : NSObject
@end
SomeClass.m
@interface SomeClass ()
@end

static NSDateFormatter *kDateFormatter;

@implementation SomeClass

+ (void)initialize
{
	static dispatch_once_t onceToken;
	dispatch_once(&onceToken, ^{
		kDateFormatter = [[NSDateFormatter alloc] init];
		[kDateFormatter setDateFormat:@"EEE, dd MMM yyyy HH:mm:ss ZZ"];
	});
}

@end

Licence

Any source in this article is released under the ISC License.