Proper way to create a singleton without @synchronized ?
Proper way to create a singleton without @synchronized ?
- Subject: Proper way to create a singleton without @synchronized ?
- From: WT <email@hidden>
- Date: Sun, 17 Apr 2011 00:04:51 -0300
After David Duncan explained dispatch_once() more clearly than the available documentation, I thought I'd give it a second look. Among other things, I wanted to replace my usage of @synchronized singletons, and dispatch_once() seemed the perfect mechanism for that.
So, I put together the class at the end of this message.
From the testing I've done - creating several threads, each invoking either [MySingleton sharedInstance] or [[MySingleton alloc] init] after a randomly selected sleep time, and running the test anew several times - it appears to behave correctly, that is, the same instance is used in every thread, it's always properly initialized (all "instances" have the same value for someInteger), and each of the three dispatch_once() blocks is executed exactly once, no matter how many threads were created.
My question for you all is then whether this is indeed correct, or whether I'm missing something that my testing may not have revealed.
Thanks in advance.
WT
===
// MySingleton.h:
#import <Foundation/Foundation.h>
@interface MySingleton: NSObject
{
NSUInteger someInteger_;
}
@property (readwrite, nonatomic, assign) NSUInteger someInteger;
+ (MySingleton*) sharedInstance;
@end
// MySingleton.m:
#import <dispatch/dispatch.h>
#import "MySingleton.h"
#import <stdlib.h>
#import <time.h>
static MySingleton* stSharedInstance = nil;
static dispatch_once_t stSharedInstanceInvoked;
static dispatch_once_t stAllocWithZoneInvoked;
static dispatch_once_t stInitInvoked;
@implementation MySingleton
@synthesize someInteger = someInteger_;
+ (MySingleton*) sharedInstance;
{
dispatch_once(&stSharedInstanceInvoked,
^{
NSLog(@"+sharedInstance block entered");
// Assignment done in +allocWithZone:.
// The autorelease message is sent to prevent XCode's
// static analyzer from issuing a warning about a possible
// memory leak. There is no leak, since the singleton is
// not meant to be deallocated, and the autorelease message
// does nothing, as per its overridden implementation below.
[[[[self class] alloc] init] autorelease];
NSLog(@"+sharedInstance block exited");
});
return stSharedInstance;
}
+ (id) allocWithZone: (NSZone*) zone;
{
dispatch_once(&stAllocWithZoneInvoked,
^{
NSLog(@"+allocWithZone: block entered");
stSharedInstance = [super allocWithZone: zone];
NSLog(@"+allocWithZone: block exited");
});
return stSharedInstance;
}
- (id) init;
{
__block id tempSelf = self;
dispatch_once(&stInitInvoked,
^{
NSLog(@"-init block entered");
tempSelf = [super init];
if (tempSelf)
{
someInteger_ = random() % 1000;
NSLog(@"Instance initialized");
}
NSLog(@"-init block exited");
});
self = tempSelf;
return self;
}
- (id) copyWithZone: (NSZone*) zone;
{
return self;
}
- (id) retain;
{
return self;
}
- (unsigned) retainCount;
{
return UINT_MAX; // Denotes an object that cannot be released.
}
- (void) release;
{
/* do nothing */
}
- (id) autorelease;
{
return self;
}
@end
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden