Що саме робить @synthesize?


148

Я бачив такий фрагмент коду:

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

//example.m
@synthesize mapView = mapView1

Яке відношення між mapViewта mapView1? Чи створює це a setі getметод для mapView1?


1
Оновлення: але з останнім набором інструментів @synthesize зараз (майже) ніколи не потрібен. Див. Відповідь на питання "Переповнення іншого стека" .
Ali Beadle

Відповіді:


228

У вашому прикладі mapView1є змінною екземпляра (ivar), фрагментом пам'яті, що належить до екземпляра класу, визначеного в example.hта example.m. mapView- це назва власності . Властивості є атрибутами об'єкта , які можуть бути лічені або встановлені з допомогою точкової нотації: myObject.mapView. Властивість не має грунтуватися на Івар, але більшість властивостей. @propertyДекларація просто говорить світові , що є властивість називається mapView.

@synthesize mapView = mapView1;

Цей рядок повідомляє компілятору створити сеттер і getter для 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, щоб сказати компілятору, що він повинен синтезувати сеттер та / або методи отримання для властивості, якщо ви не надаєте їх у блоці @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також для прив'язки властивості до змінної екземпляра через getters та setters.
Ларс Блюмберг

1
коментар jameshfisher мав на меті попередити вас про те, що ви переплутали синхронізацію та синтез у своїй відповіді. Ви користуєтесь двома взаємозамінними.
Клен

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

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

7

Згідно з документацією на яблуко @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 за замовчуванням. Компілятор також створить для вас метод getter і setter (тобто firstName, setFirstName).

Тепер, коли ви синтезуєте властивість за допомогою @synthesize firstName, ви просто говорите компілятору перейменувати мій екземпляр змінної (_firstName) на firstName. Якщо ви хочете перейменувати вашу резервну копію змінної екземпляра на інше ім'я, ви можете просто призначити інше ім'я під час синтезу імені властивості (тобто @synthesize firstName = myFirstName), зробивши це ваше майно резервне копія змінної екземпляра, названої як myFirstname.

Отже, коротше кажучи, більшість часу @synthesize використовується для перейменування змінної вашого примірника, резервної копії якої ви користуєтеся.



2

Він створює геттер і сетер для вашого об'єкта. Ви можете отримати доступ до чогось подібного:

MKMapView* m = object.mapView;

або

object.mapView = someMapViewObject

mapView1 - ім'я ivar у класі, mapView - це ім'я методів (ів) getter / setter.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.