Является ли это правильным способом реализовать одноэлемент в объективе c без дуги? [Дубликат]

Модификатор переопределения может использоваться для виртуальных методов и должен использоваться для абстрактных методов. Это означает, что компилятор использует последнюю определенную реализацию метода.

blockquote>
public class Base
{
    public virtual void DoIt()
    {
    }
}

public class Derived : Base
{
    public override void DoIt()
    {
    }
}

Base b = new Derived();
b.DoIt();                      // Calls Derived.DoIt

будет вызывать Derived.DoIt, если это переопределяет Base.DoIt.

]

Новый модификатор инструктирует компилятор использовать реализацию вашего дочернего класса вместо реализации родительского класса. Любой код, который не ссылается на ваш класс, но родительский класс будет использовать реализацию родительского класса.

blockquote>
public class Base
{
    public virtual void DoIt()
    {
    }
}

public class Derived : Base
{
    public new void DoIt()
    {
    }
}

Base b = new Derived();
Derived d = new Derived();

b.DoIt();                      // Calls Base.DoIt
d.DoIt();                      // Calls Derived.DoIt

Сначала вызовет Base.DoIt, затем Derived.DoIt. Они фактически представляют собой два совершенно разных метода, которые имеют одно и то же имя, а не производный метод, переопределяющий базовый метод.

Источник: Блог Microsoft

2
задан no.good.at.coding 12 August 2011 в 03:47
поделиться

4 ответа

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

Проверьте ответ на этот аналогичный вопрос .

2
ответ дан Community 18 August 2018 в 11:16
поделиться
  • 1
    Они могут быть эмулированы с расширением (AKA «пустая категория»), хотя, хотя я предполагаю, что он не скроет унаследованный init. – Rudy Velthuis 12 August 2011 в 04:24

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

- (id)init
{
     [NSException exceptionWithName:@"InvalidOperation" reason:@"Cannot invoke init." userInfo:nil];
}
0
ответ дан csano 18 August 2018 в 11:16
поделиться

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

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

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

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

Выбросить исключение в 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;
}
6
ответ дан kubi 18 August 2018 в 11:16
поделиться
  • 1
    И оба ответа, которые я считаю неправильными. Если метод init генерирует исключение, вы не сможете создать sharedSingleton, это первое место. Кроме того, возврат объекта singleton приведет вас к бесконечному циклу, так как singleton снова вызовет init. – Abdalrahman Shatou 7 March 2014 в 22:47
  • 2
    Я отредактировал ответ, чтобы привести примеры, так как я заглянул в детали реализации. – kubi 9 March 2014 в 02:09

Использовать 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;
}
5
ответ дан maquannene 18 August 2018 в 11:16
поделиться