Co dokładnie robi @synthesize?


148

Widziałem następujący fragment kodu:

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

//example.m
@synthesize mapView = mapView1

Jaka jest zależność między mapViewi mapView1? Czy tworzy metodę seti getdla mapView1?


1
Aktualizacja: ale z najnowszym zestawem narzędzi @synthesize jest teraz (prawie) nigdy nie potrzebne. Zobacz odpowiedź na inne pytanie dotyczące przepełnienia stosu .
Ali Beadle

Odpowiedzi:


228

W naszym przykładzie mapView1jest to zmienna instancji (ivar), część pamięci należąca do instancji klasy zdefiniowanej w example.hi example.m. mapViewto nazwa własności . Właściwości są atrybutami obiektu, który można odczytać lub ustawić za pomocą notacji kropki: myObject.mapView. Nieruchomość nie musi opierać się na ivar, ale większość nieruchomości tak. @propertyDeklaracja po prostu mówi światu, że istnieje własność nazywa mapView.

@synthesize mapView = mapView1;

Ta linia mówi kompilatorowi, aby utworzył metodę ustawiającą i pobierającą dla mapVieworaz że powinien użyć wywoływanego ivar mapView1. Bez = mapView1części kompilator założyłby, że właściwość i ivar mają tę samą nazwę. (W tym przypadku spowodowałoby to błąd kompilatora, ponieważ nie jest wywoływana żadna funkcja ivar mapView).

Wynik tego @synthesizestwierdzenia jest podobny do tego, gdy sam dodałeś ten kod:

-(MKMapView *)mapView
{
   return mapView1;
}

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

Jeśli sam dodasz ten kod do klasy, możesz zamienić @synthesizeinstrukcję na

@dynamic mapView;

Najważniejsze jest, aby mieć bardzo jasne koncepcyjne rozróżnienie między bluszczami a nieruchomościami. To naprawdę dwie bardzo różne koncepcje.


31

@synthesize tworzy metodę pobierającą i ustawiającą dla zmiennej.

Pozwala to określić pewne atrybuty dla zmiennych, a kiedy przypisujesz @synthesizetę właściwość zmiennej, generujesz metodę pobierającą i ustawiającą dla zmiennej.

Nazwa właściwości może być taka sama jak nazwa zmiennej. Czasami ludzie chcą, aby był inny, aby używać go w initlub dealloclub gdy parametr jest przekazywany z tą samą nazwą zmiennej.


16

Z dokumentacji :

Używasz słowa kluczowego @synthesize, aby powiedzieć kompilatorowi, że powinien zsyntetyzować metody ustawiające i / lub pobierające dla właściwości, jeśli nie podasz ich w bloku @implementation.


8

Ponieważ właśnie napotykam ten problem podczas edytowania starszego kodu, chcę zrobić dodatkowe notatki do istniejących odpowiedzi, o których należy wiedzieć.

Nawet w przypadku nowszej wersji kompilatora czasami ma znaczenie, czy pominiesz, @synthesize propertyNameczy nie .

W przypadku, gdy deklarujesz zmienną instancji bez podkreślenia, a jednocześnie ją syntetyzujesz, na przykład:

Nagłówek:

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

Realizacja:

@implementation SomeClass
@synthesize someInt;
@end

self.someIntbędzie mieć dostęp do tej samej zmiennej co someInt. Brak wiodącego podkreślenia dla ivars nie jest zgodny z konwencją nazewnictwa, ale po prostu znalazłem się w sytuacji, w której musiałem odczytać i zmodyfikować taki kod.

Ale jeśli teraz myślisz „Hej, @synthesize nie jest już ważne, ponieważ używamy nowszego kompilatora” , mylisz się! Twoja klasa będzie wtedy mieć dwa ivary , a mianowicie someIntplus _someIntzmienną generowaną automatycznie . W ten sposób self.someInti someIntnie będzie już adresować tych samych zmiennych. Jeśli nie spodziewasz się takiego zachowania, jak ja, może to przyprawić Cię o ból głowy.


"synchronizować"! = "syntetyzować"?
jameshfisher

Tak, to są 2 różne koncepcje. @synchronizeto dyrektywa określająca sposób synchronizowania wątków podczas uzyskiwania dostępu do właściwości i @synthesizesłuży do wiązania właściwości ze zmienną instancji za pomocą metod pobierających i ustawiających.
Lars Blumberg

1
Komentarz jameshfishera miał na celu ostrzeżenie, że w swojej odpowiedzi pomyliłeś synchronizację i syntezę. Używasz ich zamiennie.
Klon

1
Dzięki za poinformowanie mnie o tym! Całkowicie to nadzorowałem, zaktualizowałem odpowiedź, aby nie używać nieistniejącego słowa kluczowego @synchronize.
Lars Blumberg

W takim przypadku, Xcode 10 ostrzega o numerze: Autosynthesized property 'someInt' will use synthesized instance variable '_someInt', not existing instance variable 'someInt'. (Nie wiem, w której wersji xcode to ostrzeżenie zostało dodane.)
zwcloud

7

Zgodnie z dokumentacją firmy Apple @Synthesize służy tylko do zmiany nazw zmiennych instancji. Na przykład

@property NSString *str;

@synthesize str = str2; 

Teraz w klasie, której nie możesz użyć, _strponieważ powyższa linia zmienia nazwę zmiennej instancji nastr2

@property zezwala na używanie obiektów przez obiekty z innych klas, czyli innymi słowy upublicznia obiekt.


3
Najwyraźniej począwszy od Xcode 4.4 Clang zapewnia obsługę autosyntezy deklarowanych właściwości. Dlatego w większości przypadków @synthesize nie jest już konieczne. Zobacz useyourloaf.com/blog/2012/08/01/…
huyz

5

Podczas tworzenia właściwości w @interface, właściwość ta zostanie automatycznie zwrócona przez zmienną wystąpienia o nazwie _propertyName. Więc kiedy tworzysz właściwość o nazwie firstName, za sceną kompilator domyślnie utworzy zmienną instancji o nazwie _firstName. Kompilator utworzy również dla Ciebie metodę pobierającą i ustawiającą (np. FirstName, setFirstName).

Teraz, gdy syntetyzujesz właściwość za pomocą @synthesize firstName, po prostu mówisz kompilatorowi o zmianie nazwy zmiennej instancji (_firstName) na firstName. Jeśli chcesz zmienić nazwę zmiennej instancji kopii zapasowej na inną nazwę, możesz po prostu przypisać inną nazwę podczas syntezy nazwy właściwości (np. @Synthesize firstName = myFirstName), wykonując to, twoja właściwość jest zabezpieczona przez zmienną instancji o nazwie myFirstname.

Krótko mówiąc, przez większość czasu @synthesize służyło do zmiany nazwy zmiennej instancji, której kopia zapasowa jest tworzona przez twoją właściwość.



2

Tworzy getter i setter dla twojego obiektu. Możesz uzyskać dostęp za pomocą czegoś takiego:

MKMapView* m = object.mapView;

lub

object.mapView = someMapViewObject

mapView1 to nazwa ivar w klasie, mapView to nazwa metody (metod) pobierającej / ustawiającej.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.