Tiny addition to singleton subclassing
I did tweaked the allocation in the singleton implementation, but when I made two different subclasses of the singleton, namely Batman and Superman, only the first one instantiated ever. Whenever I tried to send a message to Superman, Batman tried to respond (without such a method resulting in crash). I’ve profiled it, showing the same result, only a Batman instantiated once.
I’ve came up with a solution that adds an additional condition to singleton allocation:
if (sharedInstance == nil || [sharedInstance isKindOfClass:[self class]] == NO)
sharedInstance = [NSAllocateObject([self class], 0, NULL) init];
Seems a bit weird at the first sight, but this solved the problem. You may file an errata on this.
I’ve shared the whole class with many more tiny addition out of the scope of this post (multi-delegates, really weak delegate messaging with variable parameter count, hidden interface from clients, visible for subclasses, and more) at https://eppz.svn.beanstalkapp.com/eppzkit/
Thanks for the book, I really love it.


Thanks Geri.
Did you mean Superman and Batman both subclasses of the another base singleton class or Superman subclasses Batman? It sounded like a case of the latter to me…
- Carlo
Was this answer helpful?
LikeDislikeNo. It was surprising to me as well, but:
@interface EPPZBatman : EPPZSingleton
@interface EPPZSuperman : EPPZSingleton
#define BATMAN [EPPZBatman sharedInstance]
#define SUPERMAN [EPPZSuperman sharedInstance]
And at the client code (https://eppz.svn.beanstalkapp.com/eppzkit/trunk/EPPZKit/EPPZKitViewController.m) simply:
- (void)viewDidLoad
{
[super viewDidLoad];
[BATMAN addDelegate:self];
[BATMAN doThis];
[BATMAN doThese];
[BATMAN calculate];
}
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[SUPERMAN addDelegate:self];
[SUPERMAN makeThis];
[SUPERMAN makeThese];
}
Really, go and check https://eppz.svn.beanstalkapp.com/eppzkit/trunk/EPPZKit/. If you comment out just the suggested conditional in the root class sharedInstance method (https://eppz.svn.beanstalkapp.com/eppzkit/trunk/EPPZKit/EPPZSingleton.m), then you can see the malfunction in action.
Thanks for the response, by the way. Great to reach out for the author while reading, thanks again.
Was this answer helpful?
LikeDislikeI think I know what problem you are having. Both of them initialize through the same base class. After the first subclass initialized the shared instance, the second one can’t because it’s not nil. Your workaround seems logical to me. Let me think if there is a better way to do that and I’ll post an errata up here later.
Thanks,
Carlo
Was this answer helpful?
LikeDislikeI can live without the errata, just wanted you to take an eye on the problem, have your comment on it, so thanks for that.
Other ways could be to override the +(id)sharedInstance; method in the subclasses with a new static pointer for every subclass, or to maintain a collection of pointers in the base class, but none of them make it with a single additional line. I have no 4th solution recently, maybe later on.
I’ll dive into other patterns instead.
Was this answer helpful?
LikeDislikeI have used my singleton base class under many circumstances since than, and more problems got discovered.
With the “class comparing conditional” is suggested everything worked, but every time I sent message to a different singleton class during runtime, a new instance got created. So I rolled back to the original version, but the problem was still there:
The (sharedInstance == nil) condition returns NO after you instantiate the first subclass. Every (sharedInstance == nil) condition will return NO in any further +(id)sharedInstance message sent to any (!) new subclass after the first one has created.
So every +(id)sharedInstance message of any new subclass will return the instance of the first ever instantiated subclass.
I create Batman, Spiderman and Superman subclasses of EPPZSingleton base class, and instantiate them in the same order. Then every +(id)sharedInstance message will return the Batman instance here, no matter whom I message.
I think (and it seems obvious) the problem is that the statically declared instance pointer (namely static EPPZSingleton *sharedInstance = nil;) is shared across every subclass.
I tried to shrink the visibility of the pointer by move it into the +(id)sharedInstance method, but resulted in the same.
Now everything works fine with the above mentioned singleton collection method, by the way. But still, the method suggested in the book is not working in the real life with numerous subclasses (with only one it is working well).
Was this answer helpful?
LikeDislike