Que fait exactement @synthesize?

148

J'ai vu le morceau de code suivant:

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

//example.m
@synthesize mapView = mapView1

Quelle est la relation entre mapViewet mapView1? Crée-t-il une méthode setet getpour mapView1?

Hoang Duy Nam
la source
1
Mise à jour: mais avec le dernier ensemble d'outils, @synthesize n'est plus (presque) plus nécessaire. Voir la réponse à une autre question de débordement de pile .
Ali Beadle

Réponses:

228

Dans votre exemple, mapView1est une variable d'instance (ivar), un élément de stockage mémoire qui appartient à une instance de la classe définie dans example.het example.m. mapViewest le nom d'une propriété . Les propriétés sont les attributs d'un objet qui peut être lu ou défini en utilisant la notation de points: myObject.mapView. Une propriété ne doit pas nécessairement être basée sur un ivar, mais la plupart des propriétés le sont. La @propertydéclaration indique simplement au monde qu'il existe une propriété appelée mapView.

@synthesize mapView = mapView1;

Cette ligne indique au compilateur de créer un setter et un getter pour mapView, et qu'il doit utiliser l'ivar appelé mapView1. Sans le= mapView1 partie, le compilateur supposerait que la propriété et ivar ont le même nom. (Dans ce cas, cela produirait une erreur de compilation, car aucun ivar n'est appelé mapView.)

Le résultat de cette @synthesizeinstruction est similaire à si vous aviez ajouté ce code vous-même:

-(MKMapView *)mapView
{
   return mapView1;
}

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

Si vous ajoutez vous-même ce code à la classe, vous pouvez remplacer le @synthesize instruction par

@dynamic mapView;

L'essentiel est d'avoir une distinction conceptuelle très claire entre les ivars et les propriétés. Ce sont vraiment deux concepts très différents.

Felixyz
la source
31

@synthesize crée un getter et un setter pour la variable.

Cela vous permet de spécifier certains attributs pour vos variables et lorsque vous attribuez @synthesizecette propriété à la variable, vous générez le getter et le setter pour la variable.

Le nom de la propriété peut être le même que le nom de la variable. Parfois, les gens veulent qu'il soit différent afin de l'utiliser dans initou deallocou lorsque le paramètre est passé avec le même nom de variable.

vodkhang
la source
16

De la documentation :

Vous utilisez le mot clé @synthesize pour indiquer au compilateur qu'il doit synthétiser les méthodes setter et / ou getter pour la propriété si vous ne les fournissez pas dans le bloc @implementation.

Dave DeLong
la source
8

Comme je viens de rencontrer ce problème lors de l'édition du code hérité, je veux prendre des notes supplémentaires sur les réponses existantes dont il faut être conscient.

Même avec une version plus récente du compilateur, cela fait parfois une différence si vous l'omettez @synthesize propertyNameou non .

Dans le cas où vous déclarez une variable d'instance sans trait de soulignement tout en la synthétisant, par exemple:

Entête:

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

La mise en oeuvre:

@implementation SomeClass
@synthesize someInt;
@end

self.someInt accédera à la même variable que someInt . Ne pas utiliser de trait de soulignement pour ivars ne suit pas les conventions de dénomination, mais je suis juste entré dans une situation où j'ai dû lire et modifier ce code.

Mais si vous pensez maintenant "Hé, @synthesize n'est plus important car nous utilisons un compilateur plus récent" vous vous trompez! Votre classe se traduira alors par deux ivars , à savoir someIntplus une _someIntvariable autogénérée . Ainsi self.someIntet someIntne traitera plus les mêmes variables. Si vous ne vous attendez pas à un tel comportement comme je l'ai fait, cela pourrait vous donner mal à la tête.

Lars Blumberg
la source
"synchronize"! = "synthétiser"?
jameshfisher
Oui, ce sont 2 concepts différents. @synchronizeest une directive pour savoir comment synchroniser les threads lors de l'accès à la propriété et @synthesizepour lier la propriété à une variable d'instance via des getters et des setters.
Lars Blumberg
1
Le commentaire de jameshfisher était destiné à vous alerter que vous avez confondu la synchronisation et la synthèse dans votre réponse. Vous utilisez les deux de manière interchangeable.
Érable
1
Merci de m'en avoir fait part! J'ai totalement supervisé cela, j'ai mis à jour la réponse pour ne pas utiliser le mot clé @synchronize non existant.
Lars Blumberg
Dans ce cas, Xcode 10 avertira sur la question: Autosynthesized property 'someInt' will use synthesized instance variable '_someInt', not existing instance variable 'someInt'. (Je ne sais pas dans quelle version de xcode cet avertissement a été ajouté.)
zwcloud
7

Selon la documentation Apple, @Synthesize est utilisé uniquement pour renommer les variables d'instance. Par exemple

@property NSString *str;

@synthesize str = str2; 

Maintenant, dans la classe, vous ne pouvez pas utiliser _strcar la ligne ci-dessus a renommé la variable d'instance enstr2

@property permet aux objets d'être utilisés par des objets dans d'autres classes, ou en d'autres termes rend l'objet public.

PT Vyas
la source
3
Apparemment, à partir de Xcode 4.4, Clang prend en charge l'autosynthèse des propriétés déclarées. Ainsi, @synthesize n'est plus nécessaire dans la plupart des cas. Voir useyourloaf.com/blog/2012/08/01/…
huyz
5

Lorsque vous créez une propriété dans @interface, cette propriété sera automatiquement rétablie par une variable d'instance nommée _propertyName. Ainsi, lorsque vous créez une propriété nommée firstName, le compilateur derrière la scène créera une variable d'instance nommée _firstName par défaut. Le compilateur créera également la méthode getter et setter pour vous (c'est-à-dire firstName, setFirstName).

Maintenant, lorsque vous synthétisez la propriété par @synthesize firstName, vous dites simplement au compilateur de renommer ma variable d'instance (_firstName) par firstName. Si vous souhaitez renommer votre variable d'instance sauvegardée avec un nom différent, vous pouvez simplement attribuer un nom différent tout en synthétisant le nom de la propriété (c'est-à-dire @synthesize firstName = myFirstName), en faisant cela, votre propriété est sauvegardée par une variable d'instance nommée myFirstname.

Donc, en bref, la plupart du temps, @synthesize sert à renommer votre variable d'instance sauvegardée par votre propriété.

Mahadev Mandale
la source
2

Il crée un getter et un setter pour votre objet. Vous pouvez accéder avec quelque chose comme ceci:

MKMapView* m = object.mapView;

ou

object.mapView = someMapViewObject

mapView1 est le nom de l'ivar dans la classe, mapView est le nom de la ou des méthodes getter / setter.

Nyx0uf
la source