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

前端 未结 3 902

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 sharedIn         


        
相关标签:
3条回答
  • 2021-01-11 17:37

    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).

    0 讨论(0)
  • 2021-01-11 17:46

    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.

    0 讨论(0)
  • 2021-01-11 17:49

    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;
    }
    
    0 讨论(0)
提交回复
热议问题