Что именно делает @synthesize?


148

Я видел следующий фрагмент кода:

//example.h
MKMapView * mapView1;
@property (nonatomic, retain) MKMapView * mapView;

//example.m
@synthesize mapView = mapView1

Какая связь между mapViewи mapView1? Это создает setи getметод для mapView1?


1
Обновление: но с последним набором инструментов @synthesize теперь (почти) никогда не нужен. Смотрите ответ на другой вопрос переполнения стека .
Али Бидл

Ответы:


228

В вашем примере mapView1это переменная экземпляра (ivar), часть памяти, которая принадлежит экземпляру класса, определенного в example.hи example.m. mapViewэто имя свойства . Свойства являются атрибутами объекта , которые могут быть считаны или установлены с помощью точечной нотации: myObject.mapView. Свойство не обязательно должно быть основано на иваре, но большинство свойств. @propertyДекларация просто говорит миру , что есть свойство называется mapView.

@synthesize mapView = mapView1;

Эта строка говорит компилятору создать для сеттера и геттера mapView, и что они должны использовать вызываемый ivar mapView1. Без = mapView1части компилятор предположил бы, что свойство и ivar имеют одно и то же имя. (В этом случае это приведет к ошибке компилятора, поскольку не вызывается ivar mapView.)

Результат этого @synthesizeутверждения аналогичен тому, если вы добавили этот код самостоятельно:

-(MKMapView *)mapView
{
   return mapView1;
}

-(void)setMapView:(MKMapView *)newMapView
{
  if (newMapView != mapView1)
  {
    [mapView1 release];
    mapView1 = [newMapView retain];
  }
}

Если вы добавите этот код в класс самостоятельно, вы можете заменить @synthesizeвыражение на

@dynamic mapView;

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


31

@synthesize создает геттер и сеттер для переменной.

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

Имя свойства может совпадать с именем переменной. Иногда люди хотят, чтобы это было отличается тем, чтобы использовать его в initили deallocили когда параметр передается с именем того же переменной.


16

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

Вы используете ключевое слово @synthesize, чтобы сообщить компилятору, что он должен синтезировать методы setter и / или getter для свойства, если вы не предоставляете их в блоке @implementation.


8

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

Даже с более новой версией компилятора это иногда имеет значение, если вы пропустите @synthesize propertyNameили нет .

В случае, если вы объявляете переменную экземпляра без подчеркивания, все еще синтезируя ее, например:

Заголовок:

@interface SomeClass : NSObject {
   int someInt;
}
@property int someInt;
@end

Реализация:

@implementation SomeClass
@synthesize someInt;
@end

self.someIntполучит доступ к той же переменной, что и someInt. Отсутствие начального подчеркивания для ivars не соответствует соглашениям по именованию, но я просто попал в ситуацию, когда мне пришлось читать и изменять такой код.

Но если вы теперь думаете: «Эй, @synthesize больше не важен, так как мы используем более новый компилятор», вы ошибаетесь! Ваш класс будет иметь два ивара , а именно someIntплюс автоматически сгенерированную_someInt переменную. Таким образом self.someIntи someIntбольше не будут обращаться к одним и тем же переменным. Если вы не ожидаете такого поведения, как я, это может привести к головной боли.


"синхронизировать"! = "синтезировать"?
jameshfisher

Да, это 2 разных понятия. @synchronizeявляется директивой о том, как синхронизировать потоки при доступе к свойству и @synthesizeпредназначена для привязки свойства к переменной экземпляра через методы получения и установки.
Ларс Блумберг

1
Комментарий jameshfisher должен был предупредить вас о том, что вы запутали синхронизацию и синтез в своем ответе. Вы используете два взаимозаменяемо.
клен

1
Спасибо, что сообщили мне об этом! Я полностью следил за этим, я обновил ответ, чтобы не использовать несуществующее ключевое слово @synchronize.
Ларс Блумберг

В этом случае Xcode 10 предупредит о проблеме: Autosynthesized property 'someInt' will use synthesized instance variable '_someInt', not existing instance variable 'someInt'. (Я не знаю, в какой версии xcode было добавлено это предупреждение.)
zwcloud

7

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

@property NSString *str;

@synthesize str = str2; 

Теперь в классе вы не можете использовать, _strпоскольку вышеприведенная строка переименовывает переменную экземпляра вstr2

@property позволяет объектам использоваться объектами в других классах или другими словами делает объект общедоступным.


3
По-видимому, начиная с Xcode 4.4, Clang обеспечивает поддержку автосинтеза объявленных свойств. Так что @synthesize больше не нужен в большинстве случаев. См. Useyourloaf.com/blog/2012/08/01/…
huyz

5

Когда вы создаете свойство в @interface, это свойство будет автоматически возвращено переменной экземпляра с именем _propertyName. Поэтому, когда вы создаете свойство с именем firstName, за компилятором сцены по умолчанию создается переменная экземпляра с именем _firstName. Компилятор также создаст для вас метод получения и установки (то есть firstName, setFirstName).

Теперь, когда вы синтезируете свойство с помощью @synthesize firstName, вы просто указываете компилятору переименовать мою переменную экземпляра (_firstName) по firstName. Если вы хотите переименовать вашу резервную копию переменной экземпляра под другим именем, вы можете просто присвоить другое имя при синтезировании имени свойства (т. Е. @Synthesize firstName = myFirstName), выполнив это действие, чтобы создать резервную копию переменной экземпляра с именем myFirstname.

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



2

Он создает геттер и сеттер для вашего объекта. Вы можете получить доступ с чем-то вроде этого:

MKMapView* m = object.mapView;

или

object.mapView = someMapViewObject

mapView1 - это имя ivar в классе, mapView - имя для метода (ов) получения / установки.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.