3

How can i make sure user do not call init, instead client should call sharedSingleton to get a shared instance.

@synthesize delegate;

- (id)init
{
    self = [super init];
    if (self) {
        // Initialization code here.
    }

    return self;
}

+ (LoginController *)sharedSingleton
{
    static LoginController *sharedSingleton;

    @synchronized(self)
    {
        if (!sharedSingleton)
            sharedSingleton = [[LoginController alloc] init];
        CdtMiscRegisterConnectionChangeListenerObjc(test_ConnectionChangeListenerCallback);
        return sharedSingleton;
    }
}
no.good.at.coding
  • 20,221
  • 2
  • 60
  • 51
Judeyou
  • 41
  • 1
  • 4

4 Answers4

6

Use UNAVAILABLE_ATTRIBUTE abolish init method, and implement initPrivate

+ (instancetype)shareInstance;

- (instancetype)init UNAVAILABLE_ATTRIBUTE;
+ (instancetype)new UNAVAILABLE_ATTRIBUTE;

implement

+ (instancetype)shareInstance {
    static MyClass *shareInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        shareInstance = [[super allocWithZone:NULL] initPrivate];
    });
    return shareInstance;
}

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

    }
    return self;
}

//  MARK: Rewrite
+ (id)allocWithZone:(struct _NSZone *)zone {
    return [MyClass shareInstance];
}

- (id)copyWithZone:(NSZone *)zone
{
    return self;
}
maquannene
  • 2,257
  • 1
  • 12
  • 10
6

I've seen it done two ways.

  1. Throw an exception inside init.
  2. Have the object returned by init be your singleton object.

Just to be clear, though, don't do this. It's unnecessary and will make your singletons overly difficult to test and subclass.

edit to add examples

Throw an exception in init

- (instancetype)init {
    [self doesNotRecognizeSelector:_cmd];
    return nil;
}

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

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

Have init return your singleton

- (instancetype)init {
    return [[self class] sharedInstance];
}

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

+ (instancetype)sharedInstance {
    static MySingleton2 *sharedInstance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[self alloc] initPrivate];
    });
    return sharedInstance;
}
kubi
  • 48,104
  • 19
  • 94
  • 118
  • And both answers I believe are wrong. If the init method throws exception you won't be able to create the sharedSingleton is the first place. Also, returning the singleton object will get you in infinite loop since the singleton will call init again. – Abdalrahman Shatou Mar 07 '14 at 20:47
  • I edited the answer to provide examples, since I did gloss over the implementation details. – kubi Mar 09 '14 at 00:09
2

Short answer: you can't; Objective-C has no concept of private methods.

Check out the answer to this similar question.

Community
  • 1
  • 1
zpasternack
  • 17,838
  • 2
  • 63
  • 81
  • 2
    They can be emulated with an extension (AKA "empty category") though, although I assume that it won't hide the inherited init. – Rudy Velthuis Aug 12 '11 at 03:24
0

You can't make methods private in Objective-C. You could raise a NSException if the wrong initializer is invoked.

- (id)init
{
     [NSException exceptionWithName:@"InvalidOperation" reason:@"Cannot invoke init." userInfo:nil];
}
csano
  • 13,266
  • 2
  • 28
  • 45