-
-
Save lukeredpath/1057420 to your computer and use it in GitHub Desktop.
@implementation MySharedThing | |
+ (id)sharedInstance | |
{ | |
DEFINE_SHARED_INSTANCE_USING_BLOCK(^{ | |
return [[self alloc] init]; | |
}); | |
} | |
@end |
#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; \ |
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.
I am afraid that in this way it can't prevent creating multiple instances by 'alloc'.
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.