Свойства и переменные экземпляра в Objective-C
Я довольно запутался в свойствах и переменных экземпляра в Objective-C.
Я примерно на полпути через Aaron Hillegass "Cocoa Программирование для Mac OS X", и все логично. Вы бы объявили класс следующим образом:
@class Something;
@interface MyClass : NSObject {
NSString *name;
NSArray *items;
Something *something;
IBOutlet NSTextField *myTextField;
}
@property (nonatomic, retain) NSString *name;
@property (nonatomic, retain) NSArray *items;
-
Так как другим объектам необходимо манипулировать нашими переменными экземпляра name
и items
, мы используем @property
/@synthesize
для создания для них accessors/mutators. В нашем классе мы не используем accessors/mutators - мы просто напрямую взаимодействуем с переменной экземпляра.
-
something
- это просто переменная экземпляра, которую мы собираемся использовать в нашем классе, и поскольку никто другой не должен ее использовать, мы не создаем для нее пару аксессуаров и мутаторов.
-
Нам нужно взаимодействовать с текстовым полем в нашем пользовательском интерфейсе, поэтому мы объявляем для него IBOutlet
, подключаем его, и мы закончили.
Все очень логично.
Однако в мире iPhone все выглядит по-другому. Люди объявляют свойства для каждой отдельной переменной экземпляра, объявляют свойства для IBOutlets
и используют accessors/mutators для взаимодействия с переменными экземпляра внутри класса (например, они пишут [self setName:@"Test"]
, а не name = @"Test"
)).
Почему? Что происходит? Являются ли эти различия конкретными для iPhone? В чем преимущества объявления свойств для всех переменных экземпляра, объявления свойств для IBOutlets
и использования аксессуаров/мутаторов в вашем собственном классе?
Ответы
Ответ 1
В мире iPhone нет сборщика мусора. Вам нужно будет тщательно управлять памятью с подсчетом ссылок. Имея это в виду, рассмотрите разницу между:
name = @"Test";
и
self.name = @"Test";
// which is equivalent to:
[self setName: @"Test"];
Если вы непосредственно задаете переменную экземпляра без предварительного рассмотрения, вы потеряете ссылку на предыдущее значение, и вы не сможете отрегулировать ее счетчик удержания (вы должны иметь release
d его вручную). Если вы получите доступ к нему через свойство, он будет обрабатываться автоматически для вас, а также увеличит счетчик сохранения вновь назначенного объекта.
Фундаментальная концепция не является специфичной для iPhone, но она становится решающей в среде без сборщика мусора.
Ответ 2
Свойства используются для создания аксессуаров для переменных экземпляра, там нет волшебства.
Вы можете реализовать те же элементы доступа вручную.
В примерах Aaron Hillegass вы можете найти примеры из 3 стратегий управления памятью для переменных-членов. Они assign/copy/retain
. Вы выбираете один из тех, которые необходимы для данной переменной.
Я предполагаю, что вы понимаете управление памятью в Objective-c...
Аксессоры скрывают сложность и различия в управлении памятью для каждой переменной.
Например:
name = @"Test"
является простым назначением, name
теперь имеет ссылку на NSString @"Test"
. Однако вы можете использовать copy
или retain
. Независимо от того, какая версия управления памятью, которую вы выбрали для доступа, скрывает сложность, и вы всегда получаете доступ к переменной с (или похожим):
[self setName:@"Test"]
[self name]
Теперь setName:
может использовать assign/copy or retain
, и вам не о чем беспокоиться.
Мое предположение заключается в том, что в руководствах iPhone используются свойства, позволяющие новым разработчикам быстрее переходить через управление памятью (даже при том, что они удобны для создания соответствующих аксессуаров со свойствами, а не для их реализации вручную).
Ответ 3
Однако в мире iPhone все выглядит по-другому. Люди объявляют свойства для каждой переменной экземпляра, объявляют свойства для IBOutlets
и используют accessors/mutators для взаимодействия с переменными экземпляра в классе (например, они пишут [self setName:@"Test"]
, а не name = @"Test"
).
Это не iPhone. За исключением методов init
и метода dealloc
, рекомендуется всегда использовать ваши аксессоры. Основное преимущество, особенно на Mac (с Cocoa Bindings), заключается в том, что использование ваших аксессуаров означает бесплатные уведомления KVO.
Причина, по которой люди "объявляют свойства для каждой отдельной переменной экземпляра", скорее всего, все их переменные экземпляра - это вещи, которые они хотят раскрывать как свойства. Если бы у них было что-то, что они хотели бы сохранить частным, они не объявили бы свойство для него в заголовочном файле. (Тем не менее, они могут сделать свойство для него в расширении класса в файле реализации, чтобы получить вышеупомянутые бесплатные уведомления KVO.)
Объявление свойств для торговых точек является, по-моему, излишним. Я не вижу в этом никакого смысла. Если вы не создадите свойство, загрузчик nib установит выход путем прямого доступа к переменной экземпляра, что отлично подходит для этой задачи.
Ответ 4
Я бы предположил, что современное развитие сделало очень сильную попытку определить, определить и применить лучшие практики.
Среди этих лучших практик мы находим непрерывность и последовательность.
Помимо аргументов в пользу использования аксессуаров в методах init
и dealloc
, аксессоры обычно должны использоваться все время (внутри и снаружи класса) для преимуществ, которые они предлагают, в том числе encapsulation, полиморфные реализации var (которые позволяют абстрагировать и рефакторинг), а также для облегчения этих передовых практик непрерывности и последовательности. Основополагающие преимущества объектно-ориентированного языка вступают в игру, когда они делают что-то таким образом и используют полноту языковых возможностей. Всегда быть последовательным в одном кодировании является одним из основных преимуществ, как обычно заявляет любой старший программист.
Ответ 5
Вы можете написать вот так
//MyClass.h
@class Something;
@interface MyClass : NSObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSArray *items;
@end
//MyClass.m
@interface MyClass()
@property (nonatomic, strong) IBOutlet NSTextField *myTextField;
@property (nonatomic, strong) Something *something;
@end