Синглтон-паттерн в objc, как сохранить приватность init? - PullRequest
3 голосов
/ 12 августа 2011

Как я могу убедиться, что пользователь не вызывает init, вместо этого клиент должен вызвать sharedSingleton, чтобы получить общий экземпляр.

@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;
    }
}

Ответы [ 4 ]

6 голосов
/ 12 августа 2011

Я видел, как это делалось двумя способами.

  1. Брось исключение внутри init.
  2. Пусть объект, возвращаемый init, будет вашим одноэлементным объектом.

Просто чтобы прояснить, не делайте этого. Это не нужно и сделает ваши синглеты слишком сложными для тестирования и подкласса.

изменить, чтобы добавить примеры

Бросить исключение в 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;
}

Пусть init вернет ваш синглтон

- (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;
}
5 голосов
/ 15 июня 2016

Используйте UNAVAILABLE_ATTRIBUTE отменить init метод и реализуйте initPrivate

+ (instancetype)shareInstance;

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

орудие

+ (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;
}
2 голосов
/ 12 августа 2011

Краткий ответ: вы не можете; Objective-C не имеет понятия частных методов.

Проверьте ответ на этот похожий вопрос .

0 голосов
/ 12 августа 2011

Вы не можете делать методы приватными в Objective-C.Вы можете вызвать NSException , если вызван неправильный инициализатор.

- (id)init
{
     [NSException exceptionWithName:@"InvalidOperation" reason:@"Cannot invoke init." userInfo:nil];
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...