Hope folks find this code useful. Please point out any defects or improvements. -ShawnErickson
The following code is an implementation of a base class that allows sub-classes to inherit singleton behavior including preventing deallocation of the singleton instance and related enforcement of the contract. This implementation is also thread safe.
(Are you sure? See: http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf) - Yes, this implementation uses synchronize (grab a lock) and not any broken double check, etc. scheme as outline in the PDF you referenced.
FTSWAbstractSingleton.h
#import <Foundation/Foundation.h>
@interface FTSWAbstractSingleton : NSObject { }
//designated initializer, subclasses must implement and call supers implementation
FTSWAbstractSingleton.m
#import “FTSWAbstractSingleton.h”
@implementation FTSWAbstractSingleton
static NSMutableDictionary *s_FTSWAbstractSingleton_singletons = nil;
// Should be considered private to the abstract singleton class, // wrap with a “sharedXxx” class method
// Should be considered private to the abstract singleton class
(id)singletonWithZone:(NSZone*)zone { id singleton = nil; Class class = [self class];
if (class == [FTSWAbstractSingleton class]) { [NSException raise:NSInternalInconsistencyException format:@”Not valid to request the abstract singleton.”]; }
@synchronized([FTSWAbstractSingleton class]) { singleton = [s_FTSWAbstractSingleton_singletons objectForKey:class]; if (singleton == nil) { singleton = NSAllocateObject(class, 0U, zone); if ((singleton = [singleton initSingleton]) != nil) { [s_FTSWAbstractSingleton_singletons setObject:singleton forKey:class]; } } }
return singleton; }
// Designated initializer for instances. If subclasses override they // must call this implementation.
// Disallow the normal default initializer for instances.
// —————————————————————————— // The following overrides attempt to enforce singleton behavior.
(id)new { return [self singleton]; }
(id)allocWithZone:(NSZone *)zone { return [self singletonWithZone:zone]; }
(id)alloc { return [self singleton]; }
(id)copy { //[self doesNotRecognizeSelector:_cmd]; //optional, do if you want to force certain usage pattern return self; }
(id)copyWithZone:(NSZone *)zone { //[self doesNotRecognizeSelector:_cmd]; //optional, do if you want to force certain usage pattern return self; }
(id)mutableCopy { //[self doesNotRecognizeSelector:_cmd]; //optional, do if you want to force certain usage pattern return self; }
(id)mutableCopyWithZone:(NSZone *)zone { //[self doesNotRecognizeSelector:_cmd]; //optional, do if you want to force certain usage pattern return self; }
(unsigned)retainCount { return UINT_MAX; }
(oneway void)release { }
(id)retain { return self; }
(id)autorelease { return self; }
(void)dealloc { [self doesNotRecognizeSelector:_cmd]; //optional, do if you want to force certain usage pattern } // ——————————————————————————
@end
The following is an example sub-class…
#import “FTSWAbstractSingleton.h”
@interface MySingleton : FTSWAbstractSingleton { …blah… }
@implementation MySingleton
(MySingleton*) sharedMySingleton { static MySingleton *s_MySingleton = nil;
@synchronized([MySingleton class]) { if (s_MySingleton == nil) { s_MySingleton = [self singleton]; } }
return s_MySingleton;
// or you could not use the static var above and just do “return [self singleton];” }
(id)initSingleton { if (self = [super initSingleton]) { …blah… }
return self; }
…blah… @end