53

Я довольно смущен свойствами и переменными экземпляра в Objective-C.Свойства и переменные экземпляра в Objective-C

Я нахожусь на полпути через «Программирование какао Аарона Хиллегасса для 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/мутаторов для них. В нашем классе мы не используем accessors/mutators - мы просто напрямую взаимодействуем с переменной экземпляра.

  • something - это просто переменная экземпляра, которую мы собираемся использовать в нашем классе, и поскольку никто другой не должен ее использовать, мы не создаем для этого пару аксессуаров и мутаторов.

  • Нам нужно взаимодействовать с текстовым полем в нашем пользовательском интерфейсе, поэтому мы объявляем для него IBOutlet, подключаем его, и все готово.

Все очень логично.

Однако в мире iPhone все выглядит по-другому. Люди объявляют свойства для каждой отдельной переменной экземпляра, объявляют свойства для IBOutlets и используют accessors/mutators для взаимодействия с переменными экземпляра в пределах класса (например, они будут писать [self setName:@"Test"], а не name = @"Test").

Почему? Что происходит? Являются ли эти различия конкретными для iPhone? В чем преимущества объявления свойств для всех переменных экземпляра, объявления свойств для IBOutlets и использования аксессуаров/мутаторов в вашем собственном классе?

+1

Для тех, кто в подобной ситуации: в дополнение к ответы на приведенные ниже, см http://stackoverflow.com/questions/1221516/does-an-iboutlet-needs- to-be-a-property-synthesized и http://stackoverflow.com/questions/1250518/what-happens-if-i-dont-retain-iboutlet для того, почему вы объявляете IBOutlets как свойства. –

ответ

29

В мире iPhone нет коллекционера мусора. Вам нужно будет тщательно управлять памятью с подсчетом ссылок. Имея это в виде, рассмотрит разницу между:

name = @"Test"; 

и

self.name = @"Test"; 
// which is equivalent to: 
[self setName: @"Test"]; 

Если вы непосредственно установить переменный экземпляр, без предварительного рассмотрения, вы потеряете ссылку на предыдущее значение, и вы можете 't отрегулируйте его количество удержания (вы должны иметь release d его вручную). Если вы получите доступ к нему через свойство, он будет обрабатываться автоматически для вас, а также увеличит счет сохранения вновь назначенного объекта.

Основополагающая концепция не является специфичной для iPhone, но она приобретает решающее значение в среде без сборщика мусора.

+0

... но, в разделе «Программирование какао для Mac OS X», Aaron Hillegass не использует сборщик мусора ... мы управляем памятью вручную ... –

+3

Стив: Я не видел гида. В любом случае, если вы не используете свойства и присваиваете переменным экземпляра * в любом месте *, независимо от того, входит ли он в класс или нет, вы должны быть осторожны с подсчетами ссылок. Кроме того, среды Mac OS X были старше, чем iPhone. Objective-C 2.0 уже был там, когда появился iPhone SDK, что привело к более интенсивному использованию свойств, чем использовались разработчики OS X. В целом, это в основном вопрос стиля, а не строгое правило. –

+0

@Mehrdad: Хорошо, это имеет смысл. Благодаря! –

6

Свойства используются для создания аксессуаров для переменных экземпляра, нет никакой магии.

Вы можете реализовать те же устройства доступа вручную.

В примерах книги Аарона Хиллегасса приведены примеры трех стратегий управления памятью для переменных-членов. Это assign/copy/retain. Вы выбираете один из тех, которые требуются для данной переменной.

Я полагаю, вы понимаете, управление памятью в Objective-C ...

Accessors скрыть сложность и различия управления памятью для каждой переменной.

Например:

name = @"Test" 

простое задание, name теперь держит ссылку на NSString @"Test". Однако вы можете решить использовать copy или retain. Независимо от того, какая версия управления памятью вы выбрали аксессор скрывает сложность, и вы всегда доступ к переменной с (или аналогичный):

[self setName:@"Test"] 
[self name] 

Теперь setName: может использовать assign/copy or retain и вам не придется беспокоиться об этом.

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

+0

ОК, это тоже имеет смысл. Благодаря! –

3

Однако в мире iPhone вещи кажутся разными. Люди объявляют свойства для каждой отдельной переменной экземпляра, объявляют свойства для IBOutlets и используют accessors/mutators для взаимодействия с переменными экземпляра в классе (например, они будут писать [self setName:@"Test"], а не name = @"Test").

Это не касается iPhone. За исключением методов init и метода dealloc, рекомендуется всегда использовать ваши устройства доступа. Основное преимущество, особенно на Mac (с привязкой к какао), заключается в том, что использование ваших аксессуаров означает бесплатные уведомления KVO.

Причина, по которой люди «объявляют свойства для каждой переменной экземпляра», скорее всего, все их переменные экземпляра - это вещи, которые они хотят раскрывать как свойства. Если бы у них было что-то, что они хотели бы сохранить частным, они не объявили бы свойство для него в заголовочном файле. (Тем не менее, они могут создать для него свойство в расширении класса в файле реализации, чтобы получить вышеупомянутые бесплатные уведомления KVO.)

Объявление свойств для торговых точек является, по-моему, излишним. Я не вижу в этом никакого смысла. Если вы не создадите свойство, загрузчик nib установит розетку прямым доступом к переменной экземпляра, что отлично подходит для этой задачи.

+0

Согласно http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/LoadingResources/CocoaNibs/CocoaNibs.html#//apple_ref/doc/uid/10000051-CH4-SW6, если вы этого не сделали сохраняйте объекты верхнего уровня после загрузки наконечника на iPhone, эти объекты будут освобождены. На объектах верхнего уровня для настольных компьютеров OS X количество удержаний составляет 1. Но использование свойств (или, по крайней мере, сеттеров/геттеров) делает более понятным, что происходит, и это особенно хорошая идея на iPhone. –

+0

Я согласен с тем, что это делает удержание явным, но в этом случае я не думаю, что это необходимо - просто помните, что выход всегда является собственником. –

+0

@Peter Hosey: Спасибо! Теперь все начинает иметь смысл. Один вопрос: почему бы вам не использовать методы accessor/mutator в методе 'init'? –

2

Я бы предположил, что современное развитие сделало очень сильную попытку определить, определить и применить лучшие практики.

Среди этих лучших практик мы находим непрерывность и согласованность.

Помимо спорят использование аксессоров в init и dealloc методов, аксессоров обычно следует использовать все время (внутри и вне класса) для выгоды, которые они предлагают, в том числе encapsulation, полиморфные реализации Var (которые оба позволяют абстрагирование и рефакторинг), а также для содействия передовому опыту непрерывности и последовательности. Фундаментальные преимущества объектно-ориентированного языка вступают в игру при выполнении таких действий и использовании полноты возможностей языка. Всегда быть последовательным в своем кодировании является одним из основных преимуществ, как обычно заявляет любой старший программист.

0

Вы можете написать как этот

//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 
Смежные вопросы