¿Qué hace exactamente @synthesize?


148

He visto el siguiente código:

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

//example.m
@synthesize mapView = mapView1

¿Cuál es la relación entre mapViewy mapView1? ¿Crea un método sety getpara mapView1?


1
Actualización: pero con el último conjunto de herramientas, @synthesize ahora (casi) nunca es necesario. Vea la respuesta a la otra pregunta de desbordamiento de pila .
Ali Beadle

Respuestas:


228

En su ejemplo, mapView1es una variable de instancia (ivar), un almacenamiento de memoria que pertenece a una instancia de la clase definida en example.hy example.m. mapViewes el nombre de una propiedad . Las propiedades son atributos de un objeto que se pueden leer o establecer mediante la notación de puntos: myObject.mapView. Una propiedad no tiene que basarse en un ivar, pero la mayoría de las propiedades sí. La @propertydeclaración simplemente le dice al mundo que hay una propiedad llamada mapView.

@synthesize mapView = mapView1;

Esta línea le dice al compilador que cree un setter y getter mapView, y que deben usar el ivar llamado mapView1. Sin la = mapView1parte, el compilador supondría que la propiedad y ivar tienen el mismo nombre. (En este caso, eso produciría un error de compilación, ya que no se llama ivarmapView ).

El resultado de esta @synthesizedeclaración es similar a si hubiera agregado este código usted mismo:

-(MKMapView *)mapView
{
   return mapView1;
}

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

Si agrega ese código a la clase usted mismo, puede reemplazar la @synthesizedeclaración con

@dynamic mapView;

Lo principal es tener una distinción conceptual muy clara entre ivars y propiedades. Son realmente dos conceptos muy diferentes.


31

@synthesize crea un getter y un setter para la variable.

Esto le permite especificar algunos atributos para sus variables y cuando @synthesizeesa propiedad de la variable genera el captador y definidor para la variable.

El nombre de la propiedad puede ser el mismo que el nombre de la variable. A veces la gente quiere que sea diferente con el fin de utilizarlo en inito dealloco cuando el parámetro se pasa con el nombre de la misma variable.


16

De la documentación :

Utiliza la palabra clave @synthesize para decirle al compilador que debe sintetizar los métodos setter y / o getter para la propiedad si no los proporciona dentro del bloque @implementation.


8

Como acabo de encontrarme con este problema al editar código heredado, quiero hacer notas adicionales a las respuestas existentes que uno debe tener en cuenta.

Incluso con una versión de compilador más nueva, a veces hace una diferencia si la omites @synthesize propertyNameo no .

En el caso de que declare una variable de instancia sin guión bajo mientras la sintetiza, como:

Encabezamiento:

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

Implementación:

@implementation SomeClass
@synthesize someInt;
@end

self.someInt accederá a la misma variable que someInt . No usar un guión bajo para ivars no sigue las convenciones de nomenclatura, pero acabo de encontrar una situación en la que tuve que leer y modificar dicho código.

Pero si ahora piensa "Hey, @synthesize ya no es importante ya que usamos un compilador más nuevo", ¡está equivocado! Su clase resultará en tener dos ivars , es decir, someIntmás una _someIntvariable autogenerada . Por lo tanto, self.someIntya someIntno abordará las mismas variables. Si no esperas tal comportamiento como lo hice, esto podría darte un dolor de cabeza para descubrir.


"synchronize"! = "sintetizar"?
jameshfisher

Sí, estos son 2 conceptos diferentes. @synchronizees una directiva sobre cómo sincronizar subprocesos al acceder a la propiedad y @synthesizees para vincular la propiedad a una variable de instancia a través de getters y setters.
Lars Blumberg

1
El comentario de jameshfisher estaba destinado a alertarlo de que ha confundido sincronizar y sintetizar en su respuesta. Usas los dos indistintamente.
Maple

1
¡Gracias por hacerme consciente de eso! Supervisé totalmente eso, actualicé la respuesta para no usar la palabra clave @synchronize no existente.
Lars Blumberg

En ese caso, Xcode 10 advertirá sobre el tema: Autosynthesized property 'someInt' will use synthesized instance variable '_someInt', not existing instance variable 'someInt'. (No sé en qué versión de xcode se agregó esta advertencia).
zwcloud

7

Según la documentación de Apple, @Synthesize se usa solo para cambiar el nombre de las variables de instancia. Por ejemplo

@property NSString *str;

@synthesize str = str2; 

Ahora en la clase no se puede usar _strya que la línea anterior cambia el nombre de la variable de instancia astr2

@property permite que los objetos sean utilizados por objetos en otras clases, o en otras palabras, hace que el objeto sea público.


3
Aparentemente, comenzando con Xcode 4.4, Clang proporciona soporte para la autosíntesis de propiedades declaradas. Entonces @synthesize ya no es necesario para la mayoría de los casos. Ver useyourloaf.com/blog/2012/08/01/…
huyz

5

Cuando crea una propiedad en @interface, esa propiedad se recuperará automáticamente mediante una variable de instancia denominada _propertyName. Entonces, cuando crea una propiedad llamada firstName, detrás del compilador de escena creará una variable de instancia llamada _firstName de manera predeterminada. El compilador también creará el método getter y setter para usted (es decir, firstName, setFirstName).

Ahora, cuando sintetiza la propiedad por @synthesize firstName, simplemente le está diciendo al compilador que cambie el nombre de mi variable de instancia (_firstName) por firstName. Si desea cambiar el nombre de su variable de instancia respaldada por un nombre diferente, simplemente puede asignar un nombre diferente mientras sintetiza el nombre de la propiedad (es decir, @synthesize firstName = myFirstName), al hacer esto, su propiedad está respaldada por una variable de instancia denominada como myFirstname.

En resumen, la mayoría de las veces @synthesize solía cambiar el nombre de su variable de instancia respaldada por su propiedad.



2

Crea getter y setter para su objeto. Puedes acceder con algo como esto:

MKMapView* m = object.mapView;

o

object.mapView = someMapViewObject

mapView1 es el nombre del ivar en la clase, mapView es el nombre de los métodos getter / setter.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.