0

Assume that I instantiate an object of class MyGreatClass in my NIB (as usual by simply dragging an "Object" to the NIB and settings its class to MyGreatClass).

I want access to that instance anywhere in my codebase, without introducing coupling, i.e. without passing objects around like crazy, and without having an outlet to it in, say, [NSApp delegate]. (The latter would make AppDelegate terribly bulky with time.)

I ask: Is the following considered a good code to accomplish this?

//imports

static MyGreatClass *theInstance = nil;

@implementation MyGreatClass

+ (MyGreatClass *)sharedInstance
{
  NSAssert(theInstance != nil, @"instance should have been loaded from NIB");
  return theInstance;
}

- (id)init //waking up from NIB will call this
{
  if (!theInstance)
    theInstance = self;
  return theInstance;
}

// ...

If this work as expected, I would after the app is loaded be able to access my instance via sharedInstance.

What do you think?

UPDATE: Hmm, on the second thought, the above init method maybe overkill. This is way simpler to think about:

- (id)init
{
  NSAssert(!theInstance, @"instance shouldn't exist yet because only "
                         @"the NIB-awaking process should call this method");
  theInstance = self;
  return theInstance;
}

Again, what do you think?

Enchilada
  • 3,859
  • 1
  • 36
  • 69
  • It would proably work, but why place it inside a nib? Why not just let the class handle the singleton behavior on its own? Example: http://getsetgames.com/2009/08/30/the-objective-c-singleton/ – vakio Mar 28 '11 at 00:08
  • Thanks for the reply. I had it in NIB in this case because the class also had some action methods that have connections from menu items. It then turned out that I needed to set that target/action programmatically at another place. Does that make sense? – Enchilada Mar 28 '11 at 01:52
  • No, because if you set the target/action programmatically then what is the connection to the nib? Only controllers should have IB outlets/actions. But f it is a singleton controller I guess that would make sense, somehow. – vakio Mar 28 '11 at 07:36
  • Possible duplicate of [Use Singleton In Interface Builder?](http://stackoverflow.com/questions/4609609/use-singleton-in-interface-builder) – Dan Rosenstark Mar 22 '16 at 21:25

1 Answers1

1

The proper way to create a singleton is to override allocWithZone: to ensure another object cannot be created. Overriding init allows the new object to be created, but not initialized. It is thrown away because the init method simply ignores it and returns the object that has been created already. Here is how I would do it:

+ (MyGreatClass *)sharedInstance {
    NSAssert(theInstance != nil, @"instance should have been created from NIB");
    return theInstance;
}

+ (MyGreatClass *)allocWithZone:(NSZone *)zone {
    if(theInstance) return theInstance;
    return [[self alloc] init];
}

- (id)init {
    if(theInstance) return theInstance;
    if(self = [super init]) {
        theInstance = self;
        // other initialization
    }
    return self;
}

- (void)release {}
- (void)dealloc {
    return;
    [super dealloc]; // Prevent compiler from issuing warning for not calling super
}

I overrode release and dealloc to ensure that the singleton would not be deallocated. If you don't do this, you should retain and autorelease it in the sharedInstance method. If you want to support multithreading, you should also synchronize access to the theInstance variable.

ughoavgfhw
  • 39,734
  • 6
  • 101
  • 123