Когда я должен использовать @synthesize явно?
Насколько я знаю, начиная с XCode 4.4 @synthesize
будет автоматически генерировать средства доступа к свойству. Но только сейчас я прочитал пример кода о NSUndoManager
и в коде он заметил, что @synthesize
добавлено явно. Подобно:
@interface RootViewController ()
@property (nonatomic, strong) NSDateFormatter *dateFormatter;
@property (nonatomic, strong) NSUndoManager *undoManager;
@end
@implementation RootViewController
//Must explicitly synthesize this
@synthesize undoManager;
Я чувствую себя озадаченным сейчас... Когда я должен добавить @synthesize
явно к моему коду?
7 ответов
Там много ответов, но и большая путаница. Я постараюсь навести порядок (или увеличить беспорядок, посмотрим...)
Давайте перестанем говорить о Xcode. XCode является IDE. Clang - это компилятор. Эта функция, которую мы обсуждаем, называется автосинтезом свойств, и это расширение языка Objective C, поддерживаемое clang, который является компилятором по умолчанию, используемым Xcode.
Просто чтобы прояснить: если вы переключитесь на gcc в XCode, вы не сможете воспользоваться этой функцией (независимо от версии XCode). Таким же образом, если вы используете текстовый редактор и компилируете с использованием clang из командной строки, вы будут.Благодаря автосинтезу вам не нужно явно синтезировать свойство, так как оно будет автоматически синтезировано компилятором как
@synthesize propertyName = _propertyName
Однако существует несколько исключений:
свойство readwrite с пользовательскими методами получения и установки
при предоставлении пользовательской реализации как getter, так и setter свойство не будет автоматически синтезировано
свойство только для чтения с пользовательским геттером
при предоставлении пользовательской реализации метода получения для свойства только для чтения, это не будет автоматически синтезировано
@dynamic
когда используешь
@dynamic propertyName
свойство не будет автоматически синтезировано (довольно очевидно, поскольку@dynamic
а также@synthesize
взаимоисключающие)свойства, объявленные в @protocol
при соответствии протоколу любое свойство, определяемое протоколом, не будет автоматически синтезировано
свойства, объявленные в категории
это тот случай, когда
@synthesize
директива не вставляется компилятором автоматически, но эти свойства также не могут быть синтезированы вручную. Хотя категории могут объявлять свойства, они вообще не могут быть синтезированы, поскольку категории не могут создавать ivars. Для полноты картины добавлю, что все еще возможно подделать синтез свойств, используя среду выполнения Objective-C.переопределенные свойства (новинка clang-600.0.51, поставляется с Xcode 6, спасибо Marc Schlüpmann)
когда вы переопределяете свойство суперкласса, вы должны явно синтезировать его
Стоит отметить, что при синтезе свойства автоматически синтезируется резервный ivar, поэтому, если синтез свойства отсутствует, ivar также будет отсутствовать, если явно не объявлено.
За исключением трех последних случаев, общая философия заключается в том, что всякий раз, когда вы вручную указываете всю информацию о свойстве (путем реализации всех методов доступа или использования @dynamic
) компилятор предположит, что вам нужен полный контроль над свойством, и отключит автосинтез для него.
Помимо случаев, перечисленных выше, единственное другое использование явного @synthesize
будет указывать другое имя ивара. Однако соглашения важны, поэтому я советую всегда использовать именование по умолчанию.
Если вы не используете явно @synthesize
компилятор будет понимать вашу собственность таким же образом, если вы написали
@synthesize undoManager=_undoManager;
тогда вы сможете написать в своем коде такие вещи, как:
[_undoManager doSomething]; // iVar
[self.undoManager doSomethingElse]; // Use generated getter
Это общее соглашение.
если ты пишешь
@synthesize undoManager;
у вас будет:
[undoManager doSomething]; // iVar
[self.undoManager doSomethingElse]; // Use generated getter
Лично я перестаю использовать @synthesize
, так как это больше не обязательно. Для меня единственная причина использовать @synthesize
это связать iVar
к @property
, Если вы хотите сгенерировать конкретный метод получения и установки для него. Но в данном фрагменте кода нет iVar
Думаю что это @synthesize
бесполезно. Но теперь я думаю, что новый вопрос "Когда использовать iVar
?", и у меня нет другого ответа, кроме" никогда "для этого!
Когда я должен добавить @synthesize
явно к моему коду?
Как правило, если это требуется: вы, вероятно, никогда не попадете в дело, где это необходимо.
Однако есть один случай, который может оказаться полезным.
Допустим, вы пишете как пользовательский метод получения, так и метод установки, но хотите, чтобы переменная экземпляра поддерживала его. (Для атомарного свойства это так же просто, как и необходимость пользовательского установщика: компилятор напишет получатель, если вы укажете установщик для одноатомного свойства, но не для атомарного свойства.)
Учти это:
@interface MyObject:NSObject
@property (copy) NSString *title;
@end
@implementation MyObject
- (NSString *)title {
return _title;
}
- (void)setTitle:(NSString *)title {
_title = [title copy];
}
@end
Это не будет работать, потому что _title
не существует Вы указали как getter, так и setter, поэтому Xcode (правильно) не создает для него переменную резервного экземпляра.
У вас есть два варианта сделать это существующим. Вы можете изменить @implementation
к этому:
@implementation MyObject {
NSString *_title;
}
- (NSString *)title {
return _title;
}
- (void)setTitle:(NSString *)title {
_title = [title copy];
}
@end
Или измените это на это:
@implementation MyObject
@synthesize title = _title;
- (NSString *)title {
return _title;
}
- (void)setTitle:(NSString *)title {
_title = [title copy];
}
@end
Другими словами, хотя синтезировать для практических целей никогда не нужно *, его можно использовать для определения переменных экземпляров, поддерживающих свойства, когда вы предоставляете метод получения / установки. Вы можете решить, какую форму вы хотите использовать.
В прошлом я предпочитал указывать переменную экземпляра в @implementation {}
, но я теперь думаю, что @synthesize
Маршрут является лучшим выбором, так как он удаляет избыточный тип и явно привязывает переменную поддержки к свойству:
- Измените тип свойства, и тип переменной экземпляра изменится.
- Измените его спецификатор хранения (например, сделайте его слабым вместо сильного или сильным вместо слабого), и квалификатор хранения изменится.
- Удалить или переименовать свойство, а
@synthesize
сгенерирует ошибку компилятора. Вы не будете в конечном итоге с переменными экземпляра.
* -Я знаю один случай, когда это было необходимо, касающееся разделения функциональности по категориям в нескольких файлах. И я не удивлюсь, если Apple исправит это, или даже уже исправила.
ОК, когда вы создаете свойство...
@property NSString *name;
Xcode автоматически синтезирует iVar, как если бы вы написали...
@synthesize name = _name;
Это означает, что вы можете получить доступ к собственности с...
self.name;
// or
_name;
Либо будет работать, но только self.name
на самом деле использует методы доступа.
Автосинтез не работает только один раз.
Если вы перезаписываете только метод установки и метод получения, то вам нужно будет синтезировать iVar.
Вам будет хорошо, если вы просто переопределите метод установки или просто переопределите метод получения. Но если вы сделаете и то, и другое, компилятор не поймет этого, и вам придется синтезировать его вручную.
Как правило, хотя.
Не делайте iVars. Просто используйте собственность. Не синтезируйте это.
Синтез свойства требуется, когда свойство объявлено в протоколе. Он не будет автоматически синтезирован в реализующем интерфейсе.
Спасибо за разъяснение этого. У меня была похожая проблема.
@synthesize firstAsset, secondAsset, audioAsset;
@synthesize activityView;
Итак, прокомментировав их, я прошел и заменил каждое вхождение, например,
self.firstAsset Кажется, я мог бы также использовать firstAsset, но я обнаружил, что скучаю по "" слишком часто.
Xcode не требует явного @synthesize
декларация.
Если ты не пишешь @synthesize
это так же, как делать:
@synthesize manager = _manager;
Пример кода может быть старым. Скоро обновят.
Вы можете получить доступ к своим свойствам, как:
[self.manager function];
Это рекомендуемое соглашение Apple. Я следую и рекомендую вам тоже!