Синтез и защищенные переменные экземпляра в "современном" 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;
}