Pergunta sobre @synthesize

Quando você cria um novo aplicativo a partir do Xcode que incorpora o CoreData, você obtém essas linhas no arquivo de implementação do delegado:

@synthesize window=_window; @synthesize managedObjectContext=__managedObjectContext; 

Quais são as diferenças entre usar apenas um sublinhado ou duplicá-lo? Qual é a diferença em escrever apenas:

 @synthesize window; 

Um sublinhado principal é uma convenção de nomenclatura útil para diferenciar entre variables ​​de instância e acessadores. Para o compilador é apenas um renomear ivar comum.

Considere a diferença (código não ARC):

 self.date = [NSDate date]; // OK, the setter releases the old value first date = [NSDate date]; // WRONG, skipping the setter causes a memory leak _date = [NSDate date]; // WRONG but easier to see it's not a local variable 

Com as variables ​​do ARC, não haverá vazamentos, mas ainda assim é errado ignorar os atributos @property:

 @property (copy) string; // ... self.string = someString; // OK, string is copied string = someString; // WRONG string is retained but not copied _string = someString; // WRONG but hopefully easier to see 

Ainda pior, algumas APIs, como os Core Data, dependem de notifications do KVC para realizar o carregamento lento. Se você pular acidentalmente os acessadores, seus dados retornarão como nulos.

Esta é a razão pela qual você frequentemente encontra @synthesize var=_var , o que faz

  • self.var uma referência de acessador (invocando setters e getters),
  • _var uma referência de access direto (ignorando setters e getters),
  • e var uma referência inválida.

Dado que @synthesize var=_var é @synthesize var=_var pelo LLVM 4.0 quando @synthesize é omitido, você pode considerar esta a convenção de nomenclatura padrão em Objective-C.

Continue lendo para mais detalhes …


Tempo de execução moderno

Em Objective-C 2.0 você declara variables ​​como esta:

 @interface User : NSObject @property (nonatomic, assign) NSInteger age; @end @implementation User { @synthesize age; // this line can be omitted since LLVM 4.0 @end 

que é traduzido pelo compilador da seguinte forma:

 @interface User : NSObject { NSInteger age; } @end @implementation User -(void)setAge:(NSInteger)newAge { age=newAge; } -(void)age { return age; } @end 

Se você preferir usar a convenção de sublinhado, apenas adicione o seguinte:

 @synthesize age=_age; 

Isso é tudo que você precisa porque, com o tempo de execução moderno , se você não fornecer uma variável de instância, o compilador adicionará uma para você . Aqui está o código que é compilado:

 @interface User : NSObject { NSInteger _age; } @end @implementation User -(void)setAge:(NSInteger)newAge { _age=newAge; } -(void)age { return _age; } @end 

O que acontece se você adicionar o ivar e o @property? Se a variável tiver o mesmo nome e tipo, o compilador a usará gerando uma nova variável. Citando a linguagem de programação Objective-C> Propriedades declaradas> Diretivas de Implementação de Propriedade :

Existem diferenças no comportamento da síntese de accesss que dependem do tempo de execução:

  • Para os tempos de execução modernos, as variables ​​de instância são sintetizadas conforme necessário. Se uma variável de instância com o mesmo nome já existir, ela será usada.

  • Para os tempos de execução herdados, as variables ​​de instância já devem estar declaradas no bloco @interface da class atual. Se uma variável de instância com o mesmo nome da propriedade existir e se seu tipo for compatível com o tipo da propriedade, ela será usada – caso contrário, você receberá um erro do compilador.

Tempo de execução legado

Mas se você precisar suportar o tempo de execução herdado, deverá fornecer uma variável de instância com o mesmo nome e tipo compatível da propriedade ou especificar outra variável de instância existente na instrução @synthesize .

Então o código legado sem sublinhado seria:

 @interface User : NSObject { NSInteger age; } @property (nonatomic, assign) NSInteger age; @end @implementation User @synthesize age; @end 

Ou se preferir a convenção de sublinhado:

 @interface User : NSObject { NSInteger _age; } @property (nonatomic, assign) NSInteger age; @end @implementation User @synthesize age = _age; @end 

Qual é a melhor maneira?

A Apple desencoraja o uso de sublinhado em methods, mas não em variables ​​!.

Apple em methods: Diretrizes de Codificação para o cocoa: Convenções Tipográficas :

Evite o uso do caractere de sublinhado como um prefixo que significa privado, especialmente em methods. A Apple reserva o uso desta convenção. O uso por terceiros pode resultar em colisões no espaço do nome; eles podem involuntariamente replace um método privado existente por um deles, com conseqüências desastrosas.

Apple em variables: propriedades declaradas e variables ​​de instância

Certifique-se de que o nome da variável de instância descreva de forma concisa o atributo armazenado. Normalmente, você não deve acessar variables ​​de instância diretamente, em vez disso você deve usar methods de access (você acessa variables ​​de instância diretamente nos methods init e dealloc). Para ajudar a sinalizar isso, prefixe os nomes das variables ​​de instância com um sublinhado (_) , por exemplo: @implementation MyClass { BOOL _showsTitle; } @implementation MyClass { BOOL _showsTitle; }

ISO / IEC 9899 7.1.3 Identificadores reservados (também conhecidos como C99):

  • Todos os identificadores que começam com um sublinhado e uma letra maiúscula ou outro sublinhado são sempre reservados para qualquer uso.
  • Todos os identificadores que começam com um sublinhado são sempre reservados para uso como identificadores com escopo de arquivo nos espaços comuns e de nome de tag.

Além disso, o sublinhado principal duplo é tradicionalmente reservado para o fornecedor do pré-processador / compilador / biblioteca. Isso evita o caso em que você usa __block em algum lugar em seu código, e a Apple introduz isso como uma nova palavra-chave não padrão.

Guia de estilo do Google Objective-C :

Nomes de Variáveis ​​Os nomes de variables ​​começam com letras minúsculas e usam maiúsculas e minúsculas para delimitar palavras. Variáveis ​​de membro de class têm sublinhados à direita . Por exemplo: myLocalVariable, myInstanceVariable_. Os membros usados ​​para ligações KVO / KVC podem começar com um sublinhado à esquerda se o uso de @property do Objective-C 2.0 não for permitido.

O sublinhado final do Google não força você a digitar mais um caractere antes de o Xcode triggersr o preenchimento automático, mas você perceberá que é uma variável de instância mais lenta se o sublinhado for um sufixo.

O sublinhado principal também é desencorajado em C ++ (consulte Quais são as regras sobre o uso de um sublinhado em um identificador de C ++? ) E propriedades de Core Data (tente adicionar um sublinhado à esquerda no modelo e você obterá “Nome deve começar com uma letra”) .

Seja o que for que você escolheu, é improvável que ocorram colisões e, se isso acontecer, você receberá um aviso do compilador. Em caso de dúvida, use o caminho padrão do LLVM: @synthesize var=_var;


Eu possuo uma edição deste post para ler A motivação para decorações ivar por Mark Dalrymple. Você pode querer dar uma olhada.

Você pode usar apenas

@síntese da janela;

entretanto, se sua variável de instância é chamada ‘window’, algumas pessoas usam uma convenção de nomenclatura de prefixar todas as variables ​​de instância com sublinhado, mas ainda preferem ter seus getters e setters sem o prefixo de sublinhado, isso é o que significa ‘window = _window’.

Não sei o que significa sublinhado duplo, mas suspeito que seja também uma questão de convenção de nomenclatura.