Cocoa Design Patterns
Learning OpenGL ES for iOS
Presentations
Buy at Amazon Now
  • Cocoa Design Patterns
    Cocoa Design Patterns
    by Erik M. Buck, Donald A. Yacktman
  • Learning OpenGL ES for iOS: A Hands-on Guide to Modern 3D Graphics Programming
    Learning OpenGL ES for iOS: A Hands-on Guide to Modern 3D Graphics Programming
    by Erik M. Buck

Errata > creating the singleton does not work

When I try to create a singleton according to the book's chapter, I end up in an endless loop.
Here is some of my code:

@interface CRA_Connection : NSObject {
...

@implementation CRA_Connection
...

+ (CRA_Connection *)sharedInstance {

NSLog(@"%@: entered +sharedInstance", [[self class] description]);

if (!_sharedInstance) {
_sharedInstance = [[[self class] hiddenAlloc] init];
}
return _sharedInstance;
}

+ (BOOL)sharedInstanceExists {
return (nil != _sharedInstance);
}

+ (id)hiddenAlloc {
NSLog(@"%@: entered +hiddenAlloc", [[self class] description]);
return [super alloc];
//TODO: [super alloc] calls this objetc's alloc method! Why?
}

+ (id)alloc {
NSLog(@"%@: entered +alloc", [[self class] description]);
return [self sharedInstance];
}

+ (id)new {
return [self alloc];
}

+ (id)allocWithZone:(NSZone *)zone {
NSLog(@"%@: entered +allocWithZone", [[self class] description]);
return [self alloc];
}

- (id)init {
NSLog(@"%@: entered -init", [[self class] description]);
if (![[self class] sharedInstanceExists]) {
if (self = [super init]) {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationWillTerminate:)
name:NSApplicationWillTerminateNotification
object:nil];
}
}
return self;
}

and this is the log it produces when calling [CRA_Connection sharedInstance]:

Running…
2011-02-12 17:35:53.868 BDFL2iCal[7483:a0f] CRA_Connection: entered +sharedInstance
2011-02-12 17:35:53.870 BDFL2iCal[7483:a0f] CRA_Connection: entered +hiddenAlloc
2011-02-12 17:35:53.874 BDFL2iCal[7483:a0f] CRA_Connection: entered +allocWithZone
2011-02-12 17:35:53.874 BDFL2iCal[7483:a0f] CRA_Connection: entered +alloc
2011-02-12 17:35:53.875 BDFL2iCal[7483:a0f] CRA_Connection: entered +sharedInstance
2011-02-12 17:35:53.875 BDFL2iCal[7483:a0f] CRA_Connection: entered +hiddenAlloc
2011-02-12 17:35:53.876 BDFL2iCal[7483:a0f] CRA_Connection: entered +allocWithZone
2011-02-12 17:35:53.877 BDFL2iCal[7483:a0f] CRA_Connection: entered +alloc
2011-02-12 17:35:53.877 BDFL2iCal[7483:a0f] CRA_Connection: entered +sharedInstance
...

Am I missing something?
February 12, 2011 | Unregistered CommenterAnsgar Asseburg
I believe that when +hiddenAlloc calls [super alloc], the NSObjetc's +alloc method calls (by polymorphism) the subclass' +allocWithZone: method.
How can this be prevented?
February 12, 2011 | Unregistered CommenterAnsgar Asseburg
Since +alloc calls +allowWithZone: I moved my redirect to +sharedInstance into +allocWithZone: and left out the +alloc method.
In the +sharedInstance method I call [super allocWithZone:nil] which bypasses the redirect of [super alloc] to [sub allocWithZone:].

This is my code now:

#pragma mark CRAConnection alloc, init, etc.

+ (CRA_Connection *)sharedInstance {

NSLog(@"%@: entered +sharedInstance", [[self class] description]);

if (!_sharedInstance) {
_sharedInstance = [[super allocWithZone:nil] init];
}
return _sharedInstance;
}

+ (BOOL)sharedInstanceExists {
return (nil != _sharedInstance);
}

+ (id)new {
return [self alloc];
}

+ (id)allocWithZone:(NSZone *)zone {
NSLog(@"%@: entered +allocWithZone", [[self class] description]);
return [self sharedInstance];
}

- (id)init {
NSLog(@"%@: entered -init", [[self class] description]);
if (![[self class] sharedInstanceExists]) {
if (self = [super init]) {
// register for NSApplicationWillTerminateNotification
// and when received dealloc
//TODO:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationWillTerminate:)
name:NSApplicationWillTerminateNotification
object:nil];
}
}
return self;
}

and this the resulting log:

Running…
2011-02-13 10:17:43.812 BDFL2iCal[8540:a0f] CRA_Connection: entered +sharedInstance
2011-02-13 10:17:43.814 BDFL2iCal[8540:a0f] CRA_Connection: entered -init

and it works.
February 13, 2011 | Unregistered CommenterAnsgar Asseburg