Требуется ли для объявленных свойств соответствующая переменная экземпляра?

101

Требуется ли для свойств в Objective-C 2.0 объявление соответствующей переменной экземпляра? Например, я привык делать что-то вроде этого:

MyObject.h

@interface MyObject : NSObject {
NSString *name;
}
@property (nonatomic, retain) NSString *name;
@end

MyObject.m

@implementation
@synthesize name;
@end

Однако что, если бы я сделал это вместо этого:

MyObject.h

@interface MyObject : NSObject {
}
@property (nonatomic, retain) NSString *name;
@end

Это все еще в силе? И чем это отличается от моего предыдущего примера?

Indragie
источник
Почему второй «MyObject.h» выделен жирным шрифтом, а не «MyObject.m»?
Ríomhaire

Ответы:

93

Если вы используете Modern Objective-C Runtime (iOS 3.x или выше, или 64-битный Snow Leopard или выше), вам не нужно определять ivars для ваших свойств в подобных случаях.

Когда вы @synthesizeвладеете недвижимостью, ивар будет синтезирован также для вас. Это позволяет избежать сценария "хрупкого ивара". Вы можете прочитать об этом на сайте « Какао с любовью».

Джбреннан
источник
71

В своем интерфейсе вы можете формально объявить переменную экземпляра между фигурными скобками, или через @propertyфигурные скобки, или и то, и другое. В любом случае они становятся атрибутами класса. Разница в том, что если вы объявляете @property, вы можете реализовать using @synthesize, который автоматически кодирует ваш получатель / установщик. Установщик автокодера инициализирует, например, целые числа и принимает значение с плавающей запятой. ЕСЛИ вы объявляете переменную экземпляра и НЕ указываете соответствующую переменную, @propertyвы не можете использовать @synthesizeи должны написать свой собственный метод получения / установки.

Вы всегда можете переопределить автокодируемый геттер / сеттер, указав свой собственный. Обычно это делается с managedObjectContextлениво загруженным свойством. Таким образом, вы объявляете свой managedObjectContextкак свойство, но затем также пишете -(NSManagedObjectContext *)managedObjectContextметод. Напомним, что метод, имеющий то же имя, что и переменная / свойство экземпляра, является методом «получения».

Метод @propertyобъявления также позволяет использовать другие параметры, такие как retainи readonly, которых нет в методе объявления переменной экземпляра. По сути, ivarэто старый способ, который @propertyрасширяет его и делает его интереснее / проще. Вы можете обратиться к любому из них, используя self. префикс или нет, это не имеет значения, если имя уникально для этого класса. В противном случае, если у вашего суперкласса то же имя свойства, что и у вас, вы должны произнести либо self.name, либо super.name, чтобы указать, о каком имени вы говорите.

Таким образом, вы увидите, что все меньше и меньше людей объявляют ivars между фигурными скобками, и вместо этого они будут просто указывать @property, а затем делать @synthesize. Вы не можете обойтись @synthesizeв своей реализации без соответствующего @property. Синтезатор знает только, какой это тип атрибута из @propertyспецификации. Оператор синтеза также позволяет вам переименовывать свойства, чтобы вы могли ссылаться на свойство по одному имени (сокращению) внутри вашего кода, но за пределами файла .h использовать полное имя. Однако с действительно крутым автозаполнением, которое теперь есть в XCode, это меньшее преимущество, но все же есть.

Надеюсь, это поможет прояснить всю путаницу и дезинформацию, которая витает вокруг.

ПапаСмурф
источник
Теперь уже не обязательно писать @synthesize. Итак, как этот ответ действителен в таком случае!
raaz
Вы НЕ ДОЛЖНЫ объявлять <code> @property ... @ synthesize </code>. Использование синтеза избавляет вас от необходимости писать геттер / сеттер в вашей реализации. Если вы не синтезируете, то вы должны использовать свой собственный геттер / сеттер
PapaSmurf
2
@PapaSmurf Это неверно. Их можно использовать @property, а не использовать @synthesizeи не реализовывать самостоятельно. Компилятор synthesizeвыполнит автоматическую настройку для вас, и вам больше не придется это писать.
jbrennan
8

он работает в обоих направлениях, но если вы не объявите их в фигурных скобках, вы не увидите их значений в отладчике в xcode.

Рикм
источник
3

Из документации:

В целом поведение свойств идентично как в современных, так и в устаревших средах выполнения (см. «Версии среды выполнения и платформы» в Руководстве по программированию среды выполнения Objective-C). Есть одно ключевое отличие: современная среда выполнения поддерживает синтез переменных экземпляра, тогда как устаревшая среда выполнения - нет.

Чтобы @synthesize работал в устаревшей среде выполнения, необходимо либо предоставить переменную экземпляра с тем же именем и совместимым типом свойства, либо указать другую существующую переменную экземпляра в операторе @synthesize. В современной среде выполнения, если вы не предоставляете переменную экземпляра, компилятор добавляет ее за вас.

Чарли Эллиотт
источник
3

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

Вам просто нужно объявить свойства, как показано ниже; он сгенерирует для вас синтезирующий код и код объявления переменной экземпляра.

@property (nonatomic, strong) NSString *name;

он будет генерировать синтезирующий код как

@synthesize name = _name;

и вы можете получить доступ к переменной экземпляра, используя _name, это похоже на объявление

NSString* _name

но если вы объявите свойство только для чтения, это как

@property (nonatomic, strong, readonly) NSString *name;

он сгенерирует код

@synthesize name;

или

@synthesize name = name; 

Таким образом, вы должны получить доступ к мгновенному имени переменной без префикса "_" любым способом, которым вы можете написать свой собственный синтезирующий код, тогда компилятор сгенерирует код для вас. ты можешь написать

@synthesize name = _name;
Шафраз Бухари
источник
1

Язык программирования Objective-C: директивы реализации свойств

Существуют различия в поведении синтеза средств доступа, которые зависят от среды выполнения (см. Также «Разница во времени выполнения»):

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

  • Для современных сред выполнения (см. «Версии среды выполнения и платформы» в Руководстве по программированию среды выполнения Objective-C) переменные экземпляра синтезируются по мере необходимости. Если переменная экземпляра с таким же именем уже существует, она используется.

Нейт
источник