Управление свойствами в init, которые устанавливаются подклассом в Objective-C

У меня есть абстрактный интерфейс в Objective-C, где каждый подкласс должен настроить свойство, а затем сделать то же самое с этим свойством в конце init. Я пытаюсь избежать дублирования кода примерно так:

Файл интерфейса

@interface Shape : NSObject

@property (nonatomic) PropertyType *prop;

- (id)init;
- (void)initProperty;

@end

Файл реализации

@implementation Shape

- (id)init
{
    if(self = [super init]) {
        [self initProperty];
        [prop doSomething];
    }
    return self;
}

- (void)initProperty
{
}

@end

Моя проблема в том, что каждому подклассу потребуется другой набор параметров, передаваемых в initProperty, чтобы правильно реализовать метод:

@implementation Rectangle

- (void)initPropertyWithRect:(CGRect)rect
{
    prop = [RectangleStuff rectangleWithRect:rect];
}

@end

@implementation Circle

- (void)initPropertyWithRadius:(CGFloat)radius
{
    prop = [CircleStuff circleWithRadius:radius];
}

@end

Есть ли чистый способ сделать то, что я пытаюсь сделать в Objective-C? Пока мои варианты выглядят так:

  1. Создайте «пакет с недвижимостью» и просто раздайте NSDictionary.
  2. Дублируйте код [property doSomething]; в каждом подклассе.
  3. Каким-то образом передать фабричный объект для инициализации, и фабричный объект создаст prop. Этот подход кажется самым чистым, но мне нужен фабричный объект, чтобы каким-то образом сохранить прямоугольник и/или радиус как внутреннее состояние, и мне это не кажется чистым.

Есть предположения?


person godel9    schedule 21.11.2013    source источник
comment
кстати, не используйте init для имен этих методов. Как вы можете прочитать в: clang.llvm.org/docs/ Методы семейства init неявно используют свой параметр self и возвращают сохраненный объект.   -  person Gabriele Petronella    schedule 22.11.2013
comment
@GabrielePetronella Спасибо за напоминание ... Я постоянно совершал эту ошибку.   -  person godel9    schedule 22.11.2013


Ответы (3)


Я бы, вероятно, выбрал № 2 (для простоты). Если свойство установлено только один раз (в методе инициализации подкласса), вы можете переопределить метод установки свойства в суперклассе и выполнить там дополнительные действия.

Непроверенный код:

- (void)setProp:(PropertyType *)prop
{
    _prop = prop; // (Assuming ARC)
    [_prop doSomething];
}
person Martin R    schedule 21.11.2013

Во-первых, я чувствую себя обязанным упомянуть, что ваша функция инициализации не должна делать ничего, кроме инициализации объекта. Тем не менее, у каждого правила есть время и место, где его можно нарушить, поэтому я предложу все возможные варианты.

Ваша функция инициализации ничем не отличается от любой другой функции. Вы можете делать что-то до и после вызова super. Хотя обычно это обескураживает, это было бы хорошим местом для этого. Ваша инициализация в вашем подклассе теперь будет выглядеть так:

- (id)init
{
    self.myProperty = value;
    self = [super init];
    if (self) {
        // more init stuff
    }
    return self;
}
person Holly    schedule 22.11.2013

В итоге я использовал вариант того, что было предложено в двух других ответах:

Shape.h

@interface Shape : NSObject

@property (nonatomic) PropertyType *prop;

- (id)initWithProperty:(PropertyType *prop);

@end

Shape.m

@implementation Shape

- (id)initWithProperty:(PropertyType *)prop
{
    if(self = [super init]) {
        _prop = prop;
        [_prop doSomething];
    }
    return self;
}

@end

Прямоугольник.m/Круг.m

@implementation Rectangle

- (void)initWithRect:(CGRect)rect
{
    return [self initWithProperty:[RectangleStuff rectangleWithRect:rect]];
}

@end

@implementation Circle

- (void)initWithRadius:(CGFloat)radius
{
    return [self initWithProperty:[CircleStuff circleWithRadius:radius]];
}

@end
person godel9    schedule 20.12.2013