O que exatamente o @synthesize faz?


148

Eu vi o seguinte pedaço de código:

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

//example.m
@synthesize mapView = mapView1

Qual é a relação entre mapViewe mapView1? Ele cria um método sete getpara mapView1?


1
Atualização: mas com o conjunto de ferramentas mais recente, o @synthesize agora (quase) nunca é necessário. Consulte a resposta para Outra pergunta de estouro de pilha .
Ali Beadle

Respostas:


228

No seu exemplo, mapView1é uma variável de instância (ivar), uma parte do armazenamento de memória que pertence a uma instância da classe definida em example.he example.m. mapViewé o nome de uma propriedade . Propriedades são atributos de um objeto que pode ser ler ou definir usando a notação de ponto: myObject.mapView. Uma propriedade não precisa ser baseada em um ivar, mas a maioria das propriedades é. A @propertydeclaração simplesmente diz ao mundo que existe uma propriedade chamada mapView.

@synthesize mapView = mapView1;

Essa linha diz ao compilador para criar um setter e um getter para mapView, e que eles devem usar o ivar chamado mapView1. Sem a = mapView1parte, o compilador assumiria que a propriedade e ivar têm o mesmo nome. (Nesse caso, isso produziria um erro do compilador, pois não há ivar chamado mapView.)

O resultado desta @synthesizedeclaração é semelhante a se você tivesse adicionado esse código:

-(MKMapView *)mapView
{
   return mapView1;
}

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

Se você mesmo adicionar esse código à classe, poderá substituir a @synthesizeinstrução por

@dynamic mapView;

O principal é ter uma distinção conceitual muito clara entre ivars e propriedades. Eles são realmente dois conceitos muito diferentes.


31

@synthesize cria um getter e um setter para a variável

Isso permite que você especifique alguns atributos para suas variáveis ​​e, quando @synthesizeessa propriedade for gerada, o getter e o setter para a variável.

O nome da propriedade pode ser o mesmo que o nome da variável. Às vezes, as pessoas querem que ele seja diferente, de modo a usá-lo em initou deallocou quando o parâmetro é passado com o nome da mesma variável.


16

A partir da documentação :

Você usa a palavra-chave @synthesize para informar ao compilador que ele deve sintetizar os métodos setter e / ou getter para a propriedade se você não os fornecer no bloco @implementation.


8

Como acabei de me deparar com esse problema ao editar o código legado, quero fazer anotações adicionais às respostas existentes de que precisamos estar cientes.

Mesmo com uma versão mais recente do compilador, às vezes faz diferença se você omitir @synthesize propertyNameou não .

No caso, você declara uma variável de instância sem sublinhado enquanto ainda a sintetiza, como:

Cabeçalho:

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

Implementação:

@implementation SomeClass
@synthesize someInt;
@end

self.someIntacessará a mesma variável que someInt. Não usar um sublinhado principal para ivars não segue as convenções de nomenclatura, mas acabei de entrar em uma situação em que precisava ler e modificar esse código.

Mas se agora você pensa "Ei, @synthesize não é mais importante porque usamos um compilador mais novo", você está errado! Sua classe resultará em dois ivars , someIntmais uma _someIntvariável gerada automaticamente . Portanto, self.someInte someIntnão abordará mais as mesmas variáveis. Se você não espera um comportamento como o meu, isso pode causar dor de cabeça para você descobrir.


"sincronizar"! = "sintetizar"?
jameshfisher

Sim, esses são 2 conceitos diferentes. @synchronizeé uma diretiva sobre como sincronizar threads ao acessar a propriedade e @synthesizeé para vincular a propriedade a uma variável de instância por meio de getters e setters.
Lars Blumberg

1
O comentário de jameshfisher foi feito para alertá-lo de que você confundiu sincronizar e sintetizar em sua resposta. Você usa os dois de forma intercambiável.
bordo

1
Obrigado por me informar disso! Eu supervisionei totalmente isso; atualizei a resposta para não usar a palavra-chave @synchronize não existente.
Lars Blumberg #

Nesse caso, o Xcode 10 avisará sobre o assunto: Autosynthesized property 'someInt' will use synthesized instance variable '_someInt', not existing instance variable 'someInt'. (Eu não sei em qual versão do Xcode foi adicionado este aviso.)
zwcloud

7

De acordo com a documentação da Apple, o @Synthesize é usado apenas para renomear variáveis ​​de instância. Por exemplo

@property NSString *str;

@synthesize str = str2; 

Agora na classe você não pode usar, _strpois a linha acima renomeia a variável de instância parastr2

@property permite que objetos sejam usados ​​por objetos em outras classes ou, por outras palavras, torna o objeto público.


3
Aparentemente, começando com o Xcode 4.4, o Clang fornece suporte para a autossíntese das propriedades declaradas. Portanto, o @synthesize não é mais necessário na maioria dos casos. Veja useyourloaf.com/blog/2012/08/01/…
huyz

5

Quando você cria uma propriedade em @interface, essa propriedade será automaticamente retornada por uma variável de instância denominada _propertyName. Portanto, quando você cria uma propriedade nomeada como firstName, o compilador por trás da cena cria uma variável de instância denominada _firstName por padrão. O compilador também criará o método getter e setter para você (por exemplo, firstName, setFirstName).

Agora, quando você sintetiza a propriedade por @synthesize firstName, está simplesmente dizendo ao compilador que renomeie minha variável de instância (_firstName) por firstName. Se você deseja renomear sua variável de instância de backup por nome diferente, basta atribuir um nome diferente enquanto sintetiza o nome da propriedade (por exemplo, @synthesize firstName = myFirstName), fazendo isso sua propriedade é copiada por uma variável de instância denominada myFirstname.

Portanto, em suma, na maioria das vezes @synthesize costumava renomear sua variável de instância com backup de sua propriedade.



2

Cria getter e setter para o seu objeto. Você pode acessar com algo assim:

MKMapView* m = object.mapView;

ou

object.mapView = someMapViewObject

mapView1 é o nome do ivar na classe, mapView é o nome do (s) método (s) getter / setter.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.