Свойства и переменные экземпляра в Objective-C - PullRequest
55 голосов
/ 12 октября 2009

Я довольно запутался в свойствах и переменных экземпляра в 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 и использования аксессоров / мутаторов в вашем собственном классе?

Ответы [ 5 ]

29 голосов
/ 12 октября 2009

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

name = @"Test";

и

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

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

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

6 голосов
/ 12 октября 2009

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

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

Вы можете найти в книге Аарона Хиллегаса примеры 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 голосов
/ 12 октября 2009

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

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

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

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

2 голосов
/ 26 сентября 2010

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

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

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

0 голосов
/ 18 марта 2013

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

//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
...