Установка значений по умолчанию для унаследованного свойства без использования аксессора

Я всегда вижу, как люди спорят о том, использовать ли установщик свойства в методе -init. Моя проблема заключается в том, как создать значение по умолчанию в подклассе для унаследованного свойства. Скажем, у нас есть класс с именем NSLawyer — класс фреймворка, который я не могу изменить — с интерфейсом, который выглядит так:

@interface NSLawyer : NSObject {
    @private
    NSUInteger _numberOfClients;
}

@property (nonatomic, assign) NSUInteger numberOfClients;

@end

И реализация, которая выглядит так:

@implementation NSLawyer

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

@end

Теперь предположим, что я хочу расширить NSLawyer. Мой подкласс будет называться SeniorPartner. А поскольку у старшего партнера должно быть много клиентов, при инициализации SeniorPartner я не хочу, чтобы экземпляр начинался с 0; Я хочу, чтобы у него было 10. Вот SeniorPartner.m:

@implementation SeniorPartner

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

        // Attempting to set the ivar directly will result in the compiler saying, 
        // "Instance variable _numberOfClients is private."

        // _numberOfClients = 10; <- Can't do this.

        // Thus, the only way to set it is with the mutator:
        self.numberOfClients = 10;

        // Or: [self setNumberOfClients:10];
    }
    return self;
}

@end

Так что же делать новичку в Objective-C? Ну, я имею в виду, есть только одна вещь, которую я могу сделать, это установить свойство. Если я что-то упускаю. Любые идеи, предложения, советы или хитрости?


person Ben Stock    schedule 30.05.2014    source источник
comment
возможно, изменить @private на @protected   -  person Kevin DiTraglia    schedule 30.05.2014
comment
@KevinDiTraglia Я должен был упомянуть, что моя проблема связана с невозможностью изменить суперкласс. Я создаю подклассы классов AppKit, таких как NSButton или NSPathControl, и, поскольку наши хорошие друзья в Apple любят смотреть, как мне больно, все их классы имеют свои ивары в своих заголовочных файлах (почти как издевательство надо мной), но я не могу их трогать. . :-( А как насчет тех ситуаций?   -  person Ben Stock    schedule 30.05.2014
comment
Можете ли вы использовать оператор стрелки c? self->numberOfFriends?   -  person stevesliva    schedule 30.05.2014
comment
@stevesliva Я действительно попробовал это и получил ту же ошибку. :-( Я просто удивлен, что никто не упомянул об этом раньше. Я единственный человек, который создает подклассы классов Apple? знание HTML в течение нескольких месяцев. Если вы хотите знать боль. Это боль.   -  person Ben Stock    schedule 30.05.2014
comment
Да, мы постоянно подклассифицируем классы Apple. Но доступ к приватным иварам и методам — очень плохая идея, они могут измениться в любое время — не делайте этого. Ивары можно объявлять в реализации только недавно, поэтому в устаревшем коде они есть в файле .h. В большинстве случаев Apple помещает частные переменные и методы в отдельный файл .h, который не предоставляется.   -  person zaph    schedule 30.05.2014
comment
@BenStock Можно ли предположить, что в реальной жизни ваши методы init возвращают self?   -  person jlehr    schedule 30.05.2014
comment
@jlehr Ха-ха, наверное, мне стоит это исправить, а? Спасибо за предупреждение.   -  person Ben Stock    schedule 31.05.2014
comment
@ Заф Да, я понял. Вот что я хочу сказать... Я не хочу иметь доступ к приватным иварам. Я просто хочу инициализировать ivar из суперкласса с другим значением. Это все. Я предполагаю, что мои самые большие проблемы с Obj-C до сих пор больше связаны с тем фактом, что у Apple все еще есть куча устаревшего кода, смешанного с новым кодом, поэтому, будучи новичком в языке (и Cocoa), он может запутаться в отношении лучшие практики, а что нет. Спасибо, что помогли мне разобраться со старыми вещами!   -  person Ben Stock    schedule 31.05.2014


Ответы (2)


Вы должны делать именно то, что у вас есть; вызвать аксессор. Объявляющий класс обычно избегает вызова собственных методов доступа в init, чтобы избежать случайного вызова переопределенного метода доступа в подклассе, который может полагаться на согласованность данных, которые вы еще не инициализировали. С другой стороны, ваш суперкласс должен быть полностью непротиворечивым к моменту запуска init подкласса, поэтому в это время нет проблем с использованием средств доступа суперкласса.

Рассмотрим распространенный и общий случай: вы хотите установить transform в подклассе UIView. Как бы вы решили это, кроме как позвонить setTransform:? Подклассы кода, отличного от Apple, ничем не отличаются.

person Rob Napier    schedule 30.05.2014
comment
Это имеет большой смысл. Я даже не думал об этом так. Спасибо. - person Ben Stock; 31.05.2014

Сделайте это @protected. В наши дни очень редко можно сделать ивар или собственность частной. Частные переменные и/или свойства лучше объявлять в реализации. В этом отношении @protected ivars/properties редко встречаются в Objective-C, но вполне нормально.

Использование сеттера как метода или с точечной нотацией просто неправильно (да, это работает, но это действительно плохая форма), если вы хотите использовать сеттеры/геттеры, объявляющие свойство.

person zaph    schedule 30.05.2014
comment
Когда я хочу что-то приватное, я обычно расширяю класс @interface в реализации (это то, что, я думаю, вы имеете в виду под объявленным в реализации), но если вы видите мой комментарий Кевину (выше), я лично не могу изменить суперкласс . Я совершенно забыл упомянуть об этом в своем первоначальном посте. Я не уверен, что именно означает ваше последнее предложение. Какой смысл сеттера, если не установить. Если у меня есть свойство color, я не могу сказать self.color = [NSColor redColor];? Я думал, что Apple рекомендовала использовать аксессоры/мутаторы внутри класса для KVC. Или вы про только в -init? - person Ben Stock; 30.05.2014
comment
Если у вас есть свойство color, вы можете сказать self.color = [NSColor redColor];, что является сокращением для [self setColor:[NSColor redColor]];, это не использование C для .. - person zaph; 30.05.2014
comment
Я понял тебя. Я неправильно понял, что вы имели в виду. Виноват. Спасибо за ваш вклад! - person Ben Stock; 31.05.2014