iosobjective-cinheritancesingletoninstancetype

Objective C - Singleton static method overriding doesn't work for multiple subclasses


What I have:

I have multiple singletons in my project and they share some scope, fields and functionality. So I decided to structurize them and create a parent class called BaseSingleton. As a singleton, it has +(instancetype) sharedInstance, so will all of its subclasses. Right now I have a BaseSingleton class and three subclasses:

+(instancetype) sharedInstance in BaseSingleton has a common implementation:

+(instancetype) sharedInstance {
    static BaseSingleton* _sharedInstance = nil;
    static dispatch_once_t once_token;
    dispatch_once(&once_token, ^{
        _sharedInstance = [[self alloc] init]; // no override for init method
    });
    return _sharedInstance;
}

What I need:

I need my Singleton subclasses to work properly when sharedInstance is invoked on them. Meaning, PublicApi returns an instance of PublicApi, UserService returns UserService and OrderStorage returns OrderStorage instance, with no need to implement sharedInstance.

What the problem is::

So I thought that utilizing instancetype in +(instancetype) sharedInstance would do the work, because using instancetype makes class method return related return type (read in NSHipster article). So if called on PublicApi or UserService, sharedInstance would return related type, which is PublicApi or UserService respectively (again, without implementing sharedInstance in neither of them).

This worked good with only one subclass (PublicApi). But when added other two subclasses, Calling sharedInstance on some of them would not exactly result in correct return type. So for example, [PublicApi sharedInstance] would return an instance of PublicApi, But [UserService sharedInstance] would also return an instance of PublicApi, same thing for OrderStorage.

I think the problem lays in static _sharedInstance in [BaseSingleton sharedInstance] implementation. [PublicApi sharedInstance] is called first during application runtime, so dispatch_once method instantiates _sharedInstance and gives it a PublicApi type. Code block inside dispatch_once is never executed again, that is why that static variable never changes its type and is returned as PublicApi in [UserService sharedInstance] and [OrderStorage sharedInstance].

Any elegant way to do what I am asking about? (Besides implementing sharedInstance for each subclass of course, that defeats the whole purpose of inheriting from BaseSingleton).


Solution

  • A common base class for singletons is a contradiction in itself.

    What should be obvious is that with your sharedSingleton implementation, there is only one dispatch_once_t token. So the code inside dispatch_once_t will only be executed once in your application. There is also only one static variable for _sharedInstance, so it cannot possibly return two different sharedInstance values.

    Don't do this.