Singleton in iOS Objective C doesn't prevent more than one instance

后端 未结 9 1549
长情又很酷
长情又很酷 2020-11-29 08:53

I know there are several threads on this, but none answer my questions.

I\'ve implemented my singleton class like this (being aware of the controversy about singleto

相关标签:
9条回答
  • 2020-11-29 09:34

    You can't make the init method private, like you would do in Java with the constructor. So nothing stops you from calling [[MyClass alloc] init] which indeed creates a different object. As long as you don't do that, but stick to the sharedInstance method, your implementation is fine.

    What you could do: have the init method raise an exception (e.g. with [self doesNotRecognizeSelector:@_cmd]) and perform the initialization in a different method (e.g. privateInit) which is not exposed in the header file.

    0 讨论(0)
  • 2020-11-29 09:40

    To prevent creating multiple objects of single class, you need to do following things. you just fine to created singleton object. but while calling init, copy, mutable copy, you need to handle such way.

    - (instancetype)init{
    
        if (!_sharedInstance) {
            _sharedInstance = [MyClass sharedInstance];
        }
        return _sharedInstance;
    }
    
    
    
    
    - (id)copy{
    
            if (!_sharedInstance) {
                _sharedInstance = [MyClass sharedInstance];
            }
            return _sharedInstance;
        }
    

    the same things for mutable copy as well. so this implementation make sure that once one instance is available throughout..

    May this help you.

    0 讨论(0)
  • 2020-11-29 09:41

    I wanted to add observation for a modern implementation of Objective-C singletons for optimal Swift interoperability. But let me start with the code. Let’s assume for a second that the class was to manage a series of requests, so I might call it a RequestManager:

    // RequestManager.h
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface RequestManager : NSObject
    
    @property (nonatomic, strong, readonly, class) RequestManager *sharedManager;
    
    - (instancetype)init NS_UNAVAILABLE;
    - (instancetype)copy NS_UNAVAILABLE;
    - (instancetype)mutableCopy NS_UNAVAILABLE;
    
    - (void)someMethod;
    
    @end
    
    NS_ASSUME_NONNULL_END
    

    And

    // RequestManager.m
    
    @implementation RequestManager
    
    + (instancetype)sharedManager {
        static RequestManager *_sharedInstance = nil;
        static dispatch_once_t oncePredicate;
        dispatch_once(&oncePredicate, ^{
            _sharedInstance = [[self alloc] init];
        });
        return _sharedInstance;
    }
    
    - (instancetype)init {
        self = [super init];
        if (self) {
            //setup code
        }
        return self;
    }
    
    - (void)someMethod { ... }
    
    @end
    

    Note:

    1. Note, I made the singleton a class property rather than a class method.

      From the Objective-C side, it is a distinction without difference, but from Swift, you can do things like MyClass.shared without the noise of the (). This is the pattern that Apple has adopted with all of their singletons.

    2. One might give the singleton a more meaningful name. For example, if the class was a RequestManager, the singleton might be called sharedManager rather than sharedInstance.

      If you do this, Swift will automatically detect the salient portion of the instance name and will expose it to Swift as shared, not sharedInstance or whatever.

      If you really want to use the name sharedInstance in your Objective-C code, then will just need to supply an explicit NS_SWIFT_NAME of shared to adopt the nice, concise, and consistent singleton naming practice in Swift:

       @property (nonatomic, strong, readonly, class) RequestManager *sharedInstance NS_SWIFT_NAME(shared);
      
    3. Note the use of NS_UNAVAILABLE. This prevents callers from accidentally instantiating their own copies. E.g. from Objective-C:

      Or from Swift:

    4. Probably needless to say, I’ve audited this for nullability, namely using the NS_ASSUME_NONNULL_BEGIN/END to make the default non-null. Or, obviously, you could just mark the singleton property as nonnull.

    0 讨论(0)
提交回复
热议问题