Cosa fa esattamente @synthesize?


148

Ho visto il seguente codice:

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

//example.m
@synthesize mapView = mapView1

Qual è la relazione tra mapViewe mapView1? Crea un metodo sete getper mapView1?


1
Aggiornamento: ma con l'ultimo set di strumenti @synthesize non è (quasi) mai necessario. Vedi la risposta ad altre domande di overflow dello stack .
Ali Beadle,

Risposte:


228

Nel tuo esempio, mapView1è una variabile di istanza (ivar), un pezzo di memoria che appartiene a un'istanza della classe definita in example.he example.m. mapViewè il nome di una proprietà . Le proprietà sono attributi di un oggetto che può essere letto o impostate utilizzando la notazione punto: myObject.mapView. Una proprietà non deve essere basata su un ivar, ma la maggior parte sono. La @propertydichiarazione dice semplicemente al mondo che esiste una proprietà chiamata mapView.

@synthesize mapView = mapView1;

Questa riga dice al compilatore di creare un setter e getter per mapViewe che dovrebbero usare l'ivar chiamato mapView1. Senza la = mapView1parte, il compilatore presuppone che la proprietà e ivar abbiano lo stesso nome. (In questo caso, ciò produrrebbe un errore del compilatore, poiché non viene chiamato ivar mapView.)

Il risultato di questa @synthesizeaffermazione è simile a se avessi aggiunto tu stesso questo codice:

-(MKMapView *)mapView
{
   return mapView1;
}

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

Se aggiungi quel codice alla classe, puoi sostituire l' @synthesizeistruzione con

@dynamic mapView;

La cosa principale è avere una chiara distinzione concettuale tra avari e proprietà. Sono davvero due concetti molto diversi.


31

@synthesize crea un getter e un setter per la variabile.

Questo ti consente di specificare alcuni attributi per le tue variabili e quando @synthesizequella proprietà sulla variabile generi il getter e il setter per la variabile.

Il nome della proprietà può essere uguale al nome della variabile. A volte le persone vogliono che sia diverso in modo da usarlo in inito dealloco quando il parametro viene passato con lo stesso nome della variabile.


16

Dalla documentazione :

Utilizzare la parola chiave @synthesize per indicare al compilatore che dovrebbe sintetizzare i metodi setter e / o getter per la proprietà se non vengono forniti all'interno del blocco @implementation.


8

Mentre mi imbatto in questo problema durante la modifica del codice legacy, voglio prendere note aggiuntive alle risposte esistenti di cui devi essere consapevole.

Anche con una versione più recente del compilatore, a volte fa la differenza se si omette @synthesize propertyNameo meno .

Nel caso in cui dichiari una variabile di istanza senza trattino basso mentre la sintetizzi ancora, come ad esempio:

Intestazione:

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

Implementazione:

@implementation SomeClass
@synthesize someInt;
@end

self.someIntaccederà alla stessa variabile di someInt. Non usare un carattere di sottolineatura per gli ivar non segue le convenzioni di denominazione ma sono appena entrato in una situazione in cui ho dovuto leggere e modificare tale codice.

Ma se ora pensi "Ehi, @synthesize non è più importante poiché utilizziamo un compilatore più recente" ti sbagli! La tua classe si tradurrà quindi in avere due ivar , ovvero someIntpiù una _someIntvariabile generata automaticamente . Quindi self.someInte someIntnon affronterà più le stesse variabili. Se non ti aspetti un comportamento simile a quello che ho fatto, questo potrebbe farti venire il mal di testa.


"synchronize"! = "synthesize"?
jameshfisher

Sì, questi sono 2 concetti diversi. @synchronizeè una direttiva su come sincronizzare i thread quando si accede alla proprietà ed @synthesizeè per associare la proprietà a una variabile di istanza tramite getter e setter.
Lars Blumberg,

1
Il commento di jameshfisher aveva lo scopo di avvisarti che hai confuso la sincronizzazione e la sintesi nella tua risposta. Usi i due in modo intercambiabile.
Maple,

1
Grazie per avermelo informato! L'ho supervisionato totalmente, ho aggiornato la risposta per non utilizzare la parola chiave @synchronize inesistente.
Lars Blumberg,

In tal caso, Xcode 10 avviserà sulla questione: Autosynthesized property 'someInt' will use synthesized instance variable '_someInt', not existing instance variable 'someInt'. (Non so in quale versione di xcode è stato aggiunto questo avviso.)
zwcloud

7

Come da documentazione Apple, @Synthesize viene utilizzato solo per rinominare le variabili di istanza. Per esempio

@property NSString *str;

@synthesize str = str2; 

Ora nella classe non è possibile utilizzare _strpoiché la riga sopra ha rinominato la variabile di istanza instr2

@property consente agli oggetti di essere utilizzati da oggetti in altre classi o, in altre parole, rende l'oggetto pubblico.


3
Apparentemente, a partire da Xcode 4.4, Clang fornisce supporto per l'autosintesi delle proprietà dichiarate. Quindi @synthesize non è più necessario nella maggior parte dei casi. Vedi useyourloaf.com/blog/2012/08/01/…
huyz,

5

Quando si crea una proprietà in @interface, tale proprietà tornerà automaticamente da una variabile di istanza denominata _propertyName. Pertanto, quando si crea una proprietà denominata firstName, dietro il compilatore della scena verrà creata una variabile di istanza denominata _firstName per impostazione predefinita. Il compilatore creerà anche il metodo getter e setter per te (ovvero firstName, setFirstName).

Ora, quando sintetizzi la proprietà con @synthesize firstName, stai semplicemente dicendo al compilatore di rinominare la mia variabile di istanza (_firstName) per firstName. Se si desidera rinominare la variabile dell'istanza di cui è stato eseguito il backup con un nome diverso, è possibile semplicemente assegnare un nome diverso durante la sintesi del nome della proprietà (ad esempio, @synthesize firstName = myFirstName), facendo in questo modo la propria proprietà viene copiata da una variabile di istanza denominata myFirstname.

Quindi, in breve, la maggior parte delle volte @synthesize utilizzava per rinominare la variabile di istanza di cui è stato eseguito il backup dalla proprietà.



2

Crea getter e setter per il tuo oggetto. Puoi accedere con qualcosa del genere:

MKMapView* m = object.mapView;

o

object.mapView = someMapViewObject

mapView1 è il nome dell'ivar nella classe, mapView è il nome dei metodi getter / setter.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.