it-swarm.com.ru

Свойства и переменные экземпляра в 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 для генерации для них аксессоров/мутаторов. В нашем классе мы не используем аксессоры/мутаторы - мы просто напрямую взаимодействуем с переменной экземпляра.

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

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

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

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

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

55
Steve Harrison

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

name = @"Test";

а также

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

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

Фундаментальная концепция не является специфичной для iPhone, но она становится критически важной в среде без сборщика мусора.

29
Mehrdad Afshari

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

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

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

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

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

Например:

name = @"Test"

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

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

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

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

6
stefanB

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

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

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

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

3
Peter Hosey

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

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

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

2
JRT

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

//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
0
Shafraz Buhary