views:

273

answers:

4

Hey All,

I'm implementing a singleton class as follows:

static Singleton* _singletonInstance;

@implementation Singleton

+(void)initialize
{ 
    _singletonInstance = [[Singleton alloc] init]; 
}

+(Singleton*)instance
{
    return(_singletonInstance);
}

initialize only gets called the first time someone calls instance. I then have a method that I can call to set up some instance variables. So it ends up looking like this.

_singleton = [Singleton instance];
[_singleton setupWithParams: blah];

When i get an instance of this singleton inside an object, it works fine the first time; However, after i dealloc and create a new copy of the object that needs an instance of the singleton, i get a BAD ACCESS error when I try to call the setup function.

Just to test things I print out the address of the instance before I make the setup call and both times they report the same address, but when i check the error log for BAD ACCESS call, it lists a completely different memory address.

Does anyone have any ideas why this pointer to the instance seems to look fine when I print it, but when I make a call to it, it is seemingly pointing to random data?

+1  A: 

Are you deallocing your _singletonInstance somewhere?

Eric Petroelje
+3  A: 

The pointer value looks valid because it used to be, but most likely the memory has been free'd, which is why what it points to looks like random data.

You've acquired one reference with your [[Singleton alloc] init] above, but is there a release somewhere else that might be executing? I bet your code is calling instance, and then release-ing later, even though your code never acquired a reference. And that shouldn't be necessary for a singleton anyways. Just a guess...

Jared Oberhaus
+1  A: 

I'm using much more complex, but very stable version of Singleton template (taken with description from Brandon "Quazie" Kwaselow Blog):

static SampleSingleton *sharedSampleSingletonDelegate = nil;

+ (SampleSingleton *)sharedInstance {
   @synchronized(self) {
      if (sharedSampleSingletonDelegate == nil) {
         [[self alloc] init]; // assignment not done here
      }
   }
   return sharedSampleSingletonDelegate;
}

+ (id)allocWithZone:(NSZone *)zone {
   @synchronized(self) {
      if (sharedSampleSingletonDelegate == nil) {
         sharedSampleSingletonDelegate = [super allocWithZone:zone];
         // assignment and return on first allocation
         return sharedSampleSingletonDelegate;
      }
   }
   // on subsequent allocation attempts return nil
   return nil;
 }

- (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;
}
Valerii Hiora
Thanks Valerii, that looks like a good thing to look into implementing.
Skyler
+1  A: 

Valerii's code is better for implementing a singleton, but the problem is almost certainly that the code that calls [Singleton instance] is operating as if it has ownership without actually taking ownership using retain, and then is later releasing it.

Look there for your bug, and read the Memory Managment Rules.

Also, in Xcode, enable NSZombieEnabled and the console will show you when you try to message the object after its been released.

Peter N Lewis
Thanks Peter, I'll deff use NSZombieEnabled next time i run into a wonky pointer call.
Skyler