public
Last active

Macro for creating your "shared instance" using GCD

  • Download Gist
ExampleClass.m
Objective-C
1 2 3 4 5 6 7 8 9 10
@implementation MySharedThing
 
+ (id)sharedInstance
{
DEFINE_SHARED_INSTANCE_USING_BLOCK(^{
return [[self alloc] init];
});
}
 
@end
GCDSingleton.h
Objective-C
1 2 3 4 5 6 7
#define DEFINE_SHARED_INSTANCE_USING_BLOCK(block) \
static dispatch_once_t pred = 0; \
__strong static id _sharedObject = nil; \
dispatch_once(&pred, ^{ \
_sharedObject = block(); \
}); \
return _sharedObject; \

This is a convenient way of creating a shared instance of an object using GCD and dispatch_once. I didn't come up with this technique (I believe I saw it first in a 2010 WWDC video) but I did wrap it up in this macro for convenience.

This code is written to use ARC (hence the __strong).

If you can't use GCD, but still want a singleton, please follow this advice.

Just wanted to say thanks. I too created a macro on the same premise to be a bit more generic:


/*!
 * @function Singleton GCD Macro
 */
#ifndef SINGLETON_GCD
#define SINGLETON_GCD(classname)                        \
                                                        \
+ (classname *)shared##classname {                      \
                                                        \
    static dispatch_once_t pred;                        \
    __strong static classname * shared##classname = nil;\
    dispatch_once( &pred, ^{                            \
        shared##classname = [[self alloc] init]; });    \
    return shared##classname;                           \
}                                                           
#endif

This assumes the init is a standard init.

Then to implement in the .h


@interface MyClass : NSObject
+ (MyClass *) sharedMyClass;
@end

and in the .m


#import "MyClass.h"

@implementation MyClass

SINGLETON_GCD(MyClass);

- (id) init {
    if ( (self = [super init]) ) {
        // Initialization code here.
    }   
    return self;
}
@end

I assume that __strong is not necessary if this is a Mac OS X app?
Also, allocWithZone can be ignored when using Garbage Collection?

Thanks again...

What if the sharedInstance is destroyed anywhere? Can it be created again?

No, it acts like a traditional singleton in that respect - only one can ever be created.

This code is error in Xcode 4.6

GCDSingleton.h:7:25: note: expanded from macro 'DEFINE_SHARED_INSTANCE_USING_BLOCK'
  return _sharedObject; \

Last \ is not need.

Thank you for sharing such a great technique! Here is a slightly modified version:

#define SHARED_INSTANCE(...) ({\
    static dispatch_once_t pred;\
    static id sharedObject;\
    dispatch_once(&pred, ^{\
        sharedObject = (__VA_ARGS__);\
    });\
    sharedObject;\
})

It allows two forms of shared object initialization: one-line

+ (instancetype) sharedInstance {
    return SHARED_INSTANCE( [[self alloc] init] );
}

// after pre-processing:

+ (instancetype) sharedInstance {
    return ({
        static dispatch_once_t pred;
        static id sharedObject;
        dispatch_once(&pred, ^{
            sharedObject = ( [[self alloc] init] );
        });
        sharedObject;
    });
}

and multi-line (notice curly braces around the block of code):

+ (instancetype) sharedInstance {
    return SHARED_INSTANCE({
        NSLog(@"creating shared instance");
        CGFloat someValue = 84 / 2.0f;
        [[self alloc] initWithSomeValue:someValue]; // no return statement
    });
}

// after pre-processing:

+ (instancetype) sharedInstance {
    return ({
        static dispatch_once_t pred;
        static id sharedObject;
        dispatch_once(&pred, ^{
            sharedObject = ({
                NSLog(@"creating shared instance");
                CGFloat someValue = 84 / 2.0f;
                [[self alloc] initWithSomeValue:someValue];
            });
        });
        sharedObject;
    });
}

It can be used in the right part of an assignment as well:

- (void) someMethod {
    MethodPrivateHelper *helper = SHARED_INSTANCE( [[MethodPrivateHelper alloc] init] );
    // do smth with the helper
}

This modification utilizes two language features: GCC compound expressions extension, which is also supported by Clang, and C99 variadic macros support.

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.