Подтвердить что ты не робот

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

4b9b3361

Ответ 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