Eugene
Eugene

Reputation: 41

Definite class name in a singleton method

Here is a sample code of a singleton method:

+ (id)sharedManager {
    static MyManager *sharedMyManager = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedMyManager = [[self alloc] init];
    });
    return sharedMyManager;
}

Is there a way to get rid of the certain class name declaration MyManager * and replace it with some abstract type like self * or instancetype?

Upvotes: 0

Views: 103

Answers (1)

Rob
Rob

Reputation: 437632

You can use id within the method, to avoid referencing the actual class name, and then specify an instancetype return type so that the compiler knows that what is being returned is an instance of this particular class:

+ (instancetype)sharedManager {
    static id sharedMyManager = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedMyManager = [[self alloc] init];
    });
    return sharedMyManager;
}

A word of warning: By implementing it this way, you can be lulled into a false sense of security that this class can now successfully be subclassed.

But this actually has problems. But if you have two different subclasses of this class, you now only have a single shared singleton (unless you override sharedManager in both of the subclasses).

For example, let's imagine you had two subclasses of this class, SubClass1 and SubClass2:

SubClass1 *shared1 = [SubClass1 sharedManager];
SubClass2 *shared2 = [SubClass2 sharedManager];

NSLog(@"%@", shared1);
NSLog(@"%@", shared2);

In this case, shared2 will not return an instance of Subclass2, because the static of sharedMyManager will be of the first subclass for which you called sharedManager. Thus shared2 will confusingly return that previous instance that was instantiated by [SubClass1 sharedManager].

For this reason, some people suggest that you avoid this instancetype/id pattern, because it suggests a degree of safe subclassing which really can cause problems in these sorts of curious edge-cases. Because of this, many will argue that you should reference the actual class names within sharedManager.

As a practical matter, I confess that I still use this instancetype/id pattern in a code snippet to facilitate easy creation of singletons, but just be aware of this limitation.

Upvotes: 2

Related Questions