6

In your opinion if I have a singleton subclass of NSObject being initialised with parameters like this:

- (MyObject *) initWithSomeParam:(NSString *)param{
    self = [super init];
    if (SharedInstance == nil){
        SharedInstance = [super init];
        SharedInstance.someProperty = param;
    }
    return self;
}

+ (MyObject *) objectWithSomeParam:(NSString *)param{
    return [[self alloc] initWithSomeParam:param];
    // Will the alloc cause a leak?
}

The user doesn't have access to the instance method, just the class. Thanks.

Matthias Bauch
  • 89,811
  • 20
  • 225
  • 247
John Lane
  • 1,112
  • 1
  • 14
  • 32
  • 2
    creating singleton is nicely described here: http://stackoverflow.com/questions/145154/what-does-your-objective-c-singleton-look-like – Rok Jarc Jun 01 '12 at 11:52
  • 1
    Or here: http://stackoverflow.com/questions/10066288/objective-c-optimizing-this-singleton-pattern – Adam Jun 01 '12 at 11:54

1 Answers1

3

That's not the normal way of implementing a singleton and you are breaking the convention of init. Better would be to create a sharedInstance class method and leave the initWithParam method to be more conventional:

static MyObject *_sharedInstance = nil;

+ (MyObject *)sharedInstance:(NSString *)param
{
    if (_sharedInstance == nil)
    {
        _sharedInstance = [MyObject alloc] initWithParam:param];
    }
    return _sharedInstance;
}

// This must be called during app termination to avoid memory leak
+ (void)cleanup
{
    [_sharedInstance release];
    _sharedInstance = nil;
}

- (id)initWithParam:(NSString *)param
{
    self = [super init];
    if (self != nil)
    {
        self.someProperty = param;
    }
    return self;
}

However, even that doesn't seem very comfortable; i.e. what happens if the user calls sharedInstance with a different parameter? Perhaps you want to keep a NSMutableDictionary of the initialized objects and create/return them depending on the parameter?

If so, you would do:

static NSMutableDictionary _sharedInstances = [[NSMutableDictionary alloc] init];

+ (MyObject *)sharedInstance:(NSString *)param
{
    MyObject *obj = [_sharedInstances objectForKey:param];
    if (obj == nil)
    {
        obj = [[MyObject alloc] initWithParam:param];
        [_sharedInstances setObject:obj forKey:param];
    }
    return obj;
}

// This must be called during app termination to avoid memory leak
+ (void)cleanup
{
    [_sharedInstances release];
    _sharedInstances = nil;
}
trojanfoe
  • 120,358
  • 21
  • 212
  • 242
  • 1
    You don't need the `cleanup` method. On app termination, all the memory allocated to the app is freed anyway. – jrturton Jun 01 '12 at 12:53
  • @jrturton Instruments will whinge though, won't it? – trojanfoe Jun 01 '12 at 12:53
  • Not sure, given that it's a static. I'd take a whinge from instruments over unnecessary code, anyway. – jrturton Jun 01 '12 at 12:55
  • @jrturton I guess it depends on how anal you want to be about leaks; compiler or other toolchain warnings mean you have to check that they the ones you expect, which adds time to your workflow anyway... – trojanfoe Jun 01 '12 at 13:01
  • If it is a static, Instruments and leaks won't complain. A static is a global (sometimes a scope limited global) and, thus, always reachable, valid, and never a true leak. – bbum Jun 01 '12 at 17:02
  • @bbum I've just tested this with a small Xcode project and you are right. Good to know. – trojanfoe Jun 01 '12 at 19:12