0

I have the following situation, i can't resolve:

@interface Deck : NSObject @interface MasterDeck : Deck @interface PlayerDeck : Deck 

Inside MasterDeck class, as part of initialization, i call

[self cutDeckImageIntoCards]; // We don't get to execute this method 

Call results in an error [PlayerDeck cutDeckImageIntoCards]: unrecognized selector sent to instance

Indeed, PlayerDeck does not have this method .. but why is it being called at all?

After looking at MasterDeck's initialization i added a few debugging statements:

static MasterDeck *gInstance = NULL; +(MasterDeck *) instance { @synchronized(self) { if (gInstance == NULL) { gInstance = [[self alloc] init]; } } return gInstance; } -(id) init { if (gInstance != NULL) { return gInstance; } // MasterDeck self = [super init]; // PlayerDeck if (self) { // Lots of stuff [self cutDeckImageIntoCards] // Some more stuff } gInstance = self; return gInstance; } 

Ok, so MasterDeck is PlayerDeck because' Deck thinks it is a PlayerDeck ... Deck confirms

Deck is created as follows:

static Deck *gInstance = NULL; +(Deck *) instance { @synchronized(self) { if (gInstance == NULL) { gInstance = [[self alloc] init]; } } return gInstance; } -(id) init { if (gInstance != NULL) { return gInstance; } self = [super init]; if (self) { // Do something } NSLog(@"Deck thinks it's a %@", [[self class ]description]); // PlayerDeck gInstance = self; return gInstance; } 

So, again

  • @interface Deck : NSObject

Assuming above Singleton Implementation, why would Deck think it's actually a PlayerDeck?

3
  • Show the code that created this object in question 'self'. You must have inadvertently created an instance of PlayerDeck Commented Dec 9, 2011 at 2:51
  • What happens if you change MasterDeck to subclass NSObject directly and independently implement what was the super's init method? If the problem goes away, that might give you a clue. Maybe Deck's init method mistakenly instantiates PlayerDeck. Commented Dec 9, 2011 at 3:06
  • @Wienke, I thought about it, does not seem that way .. I posted Deck's initialization code here as well Commented Dec 9, 2011 at 3:07

4 Answers 4

3

So the way you've written this, if you create the PlayDeck instance first, then the Deck instance is now a PlayDeck.

And then if you go to create the MasterDeck instance, your call to [super init] dutifully returns that previous PlayDeck instance.

So why is Deck a singleton at all? Deck has two subclasses that are singletons, but are you really looking for a singleton Deck also?

At a minimum, you can make this sort of work by not setting gInstance from within each init. Let the class method do that. Just return self from each of the init's. Also, remove the check for gInstance being not null, other Deck's init will always return Deck's instance once you have an instance of Deck.

But beyond that, I would rethink this idea a bit. Hope that helps.

Sign up to request clarification or add additional context in comments.

1 Comment

You will also need to remove the if (gInstance != NULL) check in Deck's init. I would remove that from all 3 really.
2

You'll probably want to separate your singleton class from the actual class.

Try implementing it as in this example,

+(id) instance { static dispatch_once_t pred; static MasterDeck *sharedInstance = nil; dispatch_once(&pred, ^{ sharedInstance = [[MasterDeck alloc] init]; }); return sharedInstance; } 

Comments

1

What happens if you replace [[self alloc] init] with [[MasterDeck alloc] init]?

It may be that somehow self is PlayerDeck. To make sure, you could NSLog([self description]) just before calling + alloc.

Edit

I assume that the interesting part of the code you have above is part of the @implementation of MasterDeck. My suggestion would be to try a lot more logging, including determining what super and [self class] are before calling [super init], although these may be misleading...

Also, as a side note, I believe that you should call [self release] in init if you are returning the previously-created instance.

What does the [super init] method look like? Can you step into it, or is it the default initializer?

Edit 2

I think you're doing singletons wrong. If you initialize a PlayerDeck, that would create a singleton in Deck which is an instance of PlayerDeck. Then later, when you initialize a MasterDeck, calling [super init] will return the instance already created by the PlayerDeck.

3 Comments

All the way until i [super init] MasterDeck is MasterDeck, past that line it becomes a PlayerDeck
Ed, in super, NSLog(@"Deck thinks it's a %@", [[self class ]description]); prints PlayerDeck. This would explain why MasterDeck thinks it's a PlayerDeck, but now ... why does Deck thinks it's a PlayerDeck?
Where specifically are you first calling +instance (or -init if you are calling that instead)? What does the line look like?
1

It looks like you try to be clever, but fact is - often the computer is even smarter. :)

Your deck class caches an instance in gInstance - in fact, it looks like it may store a Deck, a PlayerDeck, or a MasterDeck, depending on what and how you call / instantiate first. After that, this very instance is returned by that init method.

I strongly suggest to get this code clean and readable. I bet there are numerous problems with this code - but your problem is already a good example. Your logic (which should be simple, I guess) can surely be implemented much easier.

Note - I'm not against singletons, but this sort of code stacking is an absolute no-go. It's hard to get more dependency logic into those lines. ;)

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.