Safe way to create singleton with init method in Objective-C

瘦欲@ 提交于 2019-12-19 05:23:11

问题


I would like to take the GCD approach of using shared instances to the next step so I created the following code:

@implementation MyClass

static id sharedInstance;

#pragma mark Initialization

+ (instancetype)sharedInstance {
    static dispatch_once_t once;
    dispatch_once(&once, ^{
        sharedInstance = [[self alloc] init];
    });
    return sharedInstance;
}

- (instancetype)init {
    if (sharedInstance) {
        return sharedInstance;
    }
    @synchronized(self) {
        self = [super init];
        if (self) {
            sharedInstance = self;
        }
        return self;
    }
}

@end

I assume the sharedInstance method seems to be ok but I am unsure about the init method. The reason for creating this is that I don't want people using my SDK, to use the init method, and if they do ... make it bullet proof.


回答1:


Instead of transparently redirecting calls to init to the singleton implementation which can cause very confusing behaviour for the users of your SDK, I suggest not allowing to call init at all:

+ (instancetype)sharedInstance {
    static dispatch_once_t once;
    dispatch_once(&once, ^{
        sharedInstance = [[self alloc] initPrivate];
    });
    return sharedInstance;
}

- (instancetype)init {
    @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"..." userInfo:nil];
}

- (instancetype)initPrivate {
    if (self = [super init]) {
        ...
    }
    return self;
}



回答2:


I would like to suggest new ways of solving your problem.

You can use NS_UNAVAILABLE in the header file just like this:

//Header file
@interface MyClass : NSObject
+ (instancetype)sharedInstance
- (instancetype)init NS_UNAVAILABLE;
//...
@end

In this case init function will not be available from outside, will not be suggested for autocompletion, and you'll be able to normally use the init method inside implementation file.

As you are making a singleton class I would suggest you to make new method unavailable too by adding this line to the header file:

+ (instancetype)new NS_UNAVAILABLE;

There is also an old way of making methods unavailable (which can be used in header too):

- (instancetype) init __attribute__((unavailable("Use 'sharedInstance' instead of 'init' as this class is singleton.")));

This can be used if you want to prompt some message about unavailability.




回答3:


The general opinion is that trying to protect your singleton against that kind of bug is pointless. Whoever calls [[LUIMain alloc] init] and creates a singleton gets what they deserved.

And the code that you wrote isn't thread safe anyway. If I call [[LUIMain alloc] init] while someone else calls sharedInstance, sharedInstance will return a different object than on the next call. (@synchronized (self) in the init method is pointless, because a second caller will have a different self).



来源:https://stackoverflow.com/questions/29748175/safe-way-to-create-singleton-with-init-method-in-objective-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!