Синтез и защищенные переменные экземпляра в "современном" Objective-C?

Я хочу создать класс, который служит базовым (или "абстрактным") классом, который будет расширен подклассами. Лучший способ объяснить то, о чем я говорю, это несколько примеров. Вот возможный интерфейс для моего суперкласса:

#import <Cocoa/Cocoa.h>
#import "MyViewControllerDelegate.h"

@interface MyViewController : NSViewController

@property (nonatomic, weak) id<MyViewModeControllerDelegate> delegate;
@property (nonatomic, copy) NSArray *content;

@end

Писать это так приятно и чисто, но я не могу получить доступ к иварам из своих подклассов.

Проведя некоторые исследования, я пришел к выводу, что хорошим способом предоставления подклассам прямого доступа к ivars является использование @protected директива и включает любые объявления в заголовочный файл, чтобы подклассы могли видеть его:

#import <Cocoa/Cocoa.h>
#import "MyViewControllerDelegate.h"

@interface MyViewController : NSViewController {
@protected
    __weak id<MyViewControllerDelegate> _delegate;
    NSMutableArray *_content;
}

@property (nonatomic, weak) id<BSDViewModeControllerDelegate> delegate;
@property (nonatomic, copy) NSArray *content;

@end

У меня лично нет проблем с этим, и, кажется, это работает так, как я хочу (например, подклассы могут напрямую обращаться к ivars, но другие классы должны использовать средства доступа). Тем не менее, я читаю посты блога или ответы на вопросы о переполнении стека каждый день, в которых говорится, что переменные экземпляра следует просто синтезировать, или "я даже больше не касаюсь переменных экземпляра".

Дело в том, что я начал изучать Objective-C после ARC, поэтому я не до конца осознаю, каким образом разработчики должны были что-то делать в прошлом. Мне лично нравится контроль, который я имею, когда я реализую свои собственные методы получения / установки, и мне нравится иметь возможность видеть объявления переменных экземпляра, но, может быть, я старая школа. Я имею в виду, если нужно "просто позволить компилятору синтезировать переменные экземпляра", как можно включить какую-либо логику или "побочные эффекты", не реализуя кучу KVO?

Например, если мои переменные экземпляра и геттеры / сеттеры синтезированы, как мне лениво инициализировать вещи? Например, мне иногда нравится делать это:

- (NSArray *)myLazyArray
{
    if ( _myLazyArray == nil ) {
        self.myLazyArray = @[];
    }
    return _myLazyArray.copy;
}

Или как мне убедиться, что устанавливаемое значение не совпадает с текущим значением? Иногда я реализую проверку в своем методе мутатора следующим образом:

- (void)setMyLazyArray:(NSArray *)array
{
    if ( [array isEqualToArray:_myLazyArray] )
        return;
    _myLazyArray = array.mutableCopy;
}

Я прочитал всю документацию Apple, но половина их документов относится к 2008 году (или, что хуже, в некоторых случаях), поэтому я не совсем уверен, что они являются лучшим местом для получения информации по этому вопросу.

Я предполагаю, что суть моего вопроса заключается в следующем: есть ли предпочтительный "современный" способ обработки переменных экземпляра, синтеза переменных, наследования, области видимости и т. Д. В Objective-C? Бонусные баллы за ответы, которые не включают "Братан, Свифт". или "Вы не используете Swift?"

Любое руководство будет высоко ценится. Спасибо за прочтение!

1 ответ

Зачем вашим подклассам нужен доступ к вашим иварам? Ивари - это деталь реализации, и подклассы не должны этим заниматься. Побочные эффекты могут быть всевозможными, если родительский класс выполняет логику в установщике / получателе свойств. Поэтому всегда обращайтесь к ним через собственность.

Предполагая, что это в вашем подклассе, и вы переопределяете свойство get:

- (NSArray *)myLazyArray
{
    if ( super.myLazyArray == nil ) {
        // do what you need to do to populate the array
        // assign it to yourself (or super)
        self.myLazyArray = @[];
    }

    return super.myLazyArray;
}

А потом для сеттера:

- (void)setMyLazyArray:(NSArray *)array
{
    if ( [array isEqualToArray:super.myLazyArray] )
        return;
    super.myLazyArray = array.mutableCopy;
}
Другие вопросы по тегам