Re: is this enough for a singleton? (for a class cluster "placeholder")
Re: is this enough for a singleton? (for a class cluster "placeholder")
- Subject: Re: is this enough for a singleton? (for a class cluster "placeholder")
- From: Shaun Wexler <email@hidden>
- Date: Fri, 13 Feb 2004 08:08:38 -0800
On Feb 11, 2004, at 1:22 PM, Ben Dougall wrote:
i got this code from the archives for a singleton object:
+ (id)allocWithZone:(NSZone *)zone {
if ([MyAbstractClass self] == self)
return NSAllocateObject([MyConcreteClass self], 0, zone);
return [super allocWithZone:zone];
}
don't quite understand it -- will that give an ok/perfectly fine
singleton implementation? usually the singleton implementations that
i've seen involve a static variable in the class, but i know there's a
variety of ways to do singletons. is there something else that needs
to be done further to the above code, or is that it, so far as the
singleton aspect of it goes?
(not sure if this throws a different light on it or not -- both the
above code and what i want a singleton for, is for the abstract class
of a class cluster - a placeholder - the thing that vends as it were.
the above code is from here:
<http://cocoa.mamasam.com/COCOADEV/2001/09/2/12499.php>)
thanks, ben.
One of the problems with a lot of the different singleton base-classes
you'll see is that you can still call the singleton method -init.
Unless each subclass has strict preventative measures to disallow
reentrance (which most init methods don't implement), then the
singleton can be broken accidentally. My "hardcore" singleton class is
fairly bulletproof; it "swizzles" each subclass init method IMP, to
prevent it from accidentally being called again and corrupting the
singleton instance. I'll attach the .m below.
For efficiency, give each of your subclasses their own class
accessor/instantiation method, such as this:
+ (id)sharedSerialPortRegistry
{
static id sharedSerialPortRegistry = nil;
if (!sharedSerialPortRegistry) {
sharedSerialPortRegistry = [self sharedInstance];
}
return sharedSerialPortRegistry;
}
--
Shaun Wexler
MacFOH
http://www.macfoh.com
/
*=======================================================================
=====================*/
//
// SKWSingletonObject.m
// SKWBase
//
// Created by Shaun Wexler on Sun Aug 31 2003.
// Copyright (c) 2003 SKW Development. All rights reserved.
//
/
*=======================================================================
=====================*/
#import "SKWSingletonObject.h"
#import <objc/objc-runtime.h>
@implementation SKWSingletonObject
static NSMutableDictionary *sharedInstances = nil;
static NSRecursiveLock *sharedInstancesLock = nil;
static Method abstractInit = NULL;
static Method disabledInit = NULL;
+ (void)initialize
{
@synchronized(self)
{
if (!sharedInstances) {
sharedInstances = [[NSMutableDictionary alloc] init];
sharedInstancesLock = [[NSRecursiveLock alloc] init];
abstractInit = class_getInstanceMethod(self, @selector(init));
disabledInit = class_getInstanceMethod(self,
@selector(singletonInitDisabled));
}
}
}
+ (id)sharedInstance
{
Class class = [self class];
id singleton = nil;
@try {
[sharedInstancesLock lock];
singleton = [sharedInstances objectForKey:class];
if (!singleton) {
singleton = class_createInstanceFromZone(class, 0U, [self zone]);
if (singleton) {
Method singletonInit = class_getInstanceMethod(class,
@selector(init));
[sharedInstances setObject:singleton forKey:class];
if (singletonInit) {
[singleton init];
if (singletonInit->method_imp != abstractInit->method_imp) {
singletonInit->method_imp = disabledInit->method_imp;
}
}
}
}
}
@catch (NSException *exception) {
NSLog(@"%@ raised %@: %@", class, [exception name], [exception
reason]);
}
@finally {
[sharedInstancesLock unlock];
}
return singleton;
}
- (id)singletonInitDisabled
{
[NSException raise:NSInternalInconsistencyException
format:@"can't re-init %@ sharedInstance", [self class]];
return self;
}
+ (id)new
{
return [self sharedInstance];
}
+ (id)allocWithZone:(NSZone *)zone
{
return [self sharedInstance];
}
+ (id)alloc
{
return [self sharedInstance];
}
- (id)init
{
return [super init];
}
- (id)copy
{
[self doesNotRecognizeSelector:_cmd];
return self;
}
- (id)copyWithZone:(NSZone *)zone
{
[self doesNotRecognizeSelector:_cmd];
return self;
}
- (id)mutableCopy
{
[self doesNotRecognizeSelector:_cmd];
return self;
}
- (id)mutableCopyWithZone:(NSZone *)zone
{
[self doesNotRecognizeSelector:_cmd];
return self;
}
- (unsigned)retainCount
{
return UINT_MAX;
}
- (oneway void)release
{
}
- (id)retain
{
return self;
}
- (id)autorelease
{
return self;
}
- (void)dealloc
{
[self doesNotRecognizeSelector:_cmd];
}
@end
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.