Como você nomeia seus valores de instância/parâmetro?
-
08-06-2019 - |
Pergunta
Sendo novo no programador Objective-C (mas um programador C/++ de longo prazo), estou procurando conselhos/recomendações sobre convenções de nomenclatura para variáveis.
Minha preferência pessoal seria utilizar um prefixo para variáveis de instância, tanto para maior clareza nas funções quanto para evitar o sombreamento dos parâmetros da função.No entanto, sou fã de propriedades que excluem prefixos (a menos que você também prefixe os nomes de suas propriedades, o que não funciona muito bem e parece idiota).Da mesma forma, eu poderia usar a convenção "self.variable", mas somente se eu transformar EVERYTHING em uma propriedade.
Então, dado o código abaixo, qual é o seu estilo de nomenclatura preferido para variáveis de instância/função?E se você não se incomoda, como você lida com o sombreamento dos parâmetros de função?
@interface GridItem : NSObject
{
CGRect _rect;
...
}
@end
-(void) initFromRect:(CGRect)rect
{
_rect = rect;
...
}
Saúde!
Solução
A maioria dos projetos de cacau usa o underbar como um recurso não-IBOutlet
prefixo da variável de instância e não use prefixo para IBOutlet
variáveis de instância.
A razão pela qual não uso underbars para IBOutlet
variáveis de instância é que quando um arquivo nib é carregado, se você tiver um método setter para uma tomada conectada, esse setter será chamado. No entanto esse mecanismo faz não use codificação de valor-chave, portanto, um IBOutlet cujo nome é prefixado com uma barra inferior (por exemplo. _myField
) vai não ser definido, a menos que o setter tenha o mesmo nome da tomada (por exemplo. set_myField:
), o que é fora do padrão e grosseiro.
Além disso, esteja ciente de que o uso de propriedades como self.myProp
é não o mesmo que acessar variáveis de instância.Você é enviando uma mensagem quando você usa uma propriedade, como se você usasse notação de colchetes como [self myProp]
.Todas as propriedades fornecem uma sintaxe concisa para especificar o getter e o setter em uma única linha e permitem sintetizar sua implementação;na verdade, eles não causam curto-circuito no mecanismo de envio de mensagens.Se você quiser acessar uma variável de instância diretamente, mas prefixá-la com self
você precisa tratar self
como um ponteiro, como self->myProp
que realmente é um acesso de campo no estilo C.
Finalmente, nunca use a notação húngara ao escrever código Cocoa e evite outros prefixos como "f" e "m_" - isso marcará o código como tendo sido escrito por alguém que não "entendeu" e fará com que ele ser visto com suspeita por outros desenvolvedores do Cocoa.
Em geral, siga os conselhos do Diretrizes de codificação para cacau documento no Conexão de desenvolvedor Apple, e outros desenvolvedores serão capazes de entender e entender seu código, e seu código funcionará bem com todos os recursos do Cocoa que usam introspecção em tempo de execução.
Esta é a aparência de uma classe de controlador de janela, usando minhas convenções:
// EmployeeWindowController.h
#import <AppKit/NSWindowController.h>
@interface EmployeeWindowController : NSWindowController {
@private
// model object this window is presenting
Employee *_employee;
// outlets connected to views in the window
IBOutlet NSTextField *nameField;
IBOutlet NSTextField *titleField;
}
- (id)initWithEmployee:(Employee *)employee;
@property(readwrite, retain) Employee *employee;
@end
// EmployeeWindowController.m
#import "EmployeeWindowController.h"
@implementation EmployeeWindowController
@synthesize employee = _employee;
- (id)initWithEmployee:(Employee *)employee {
if (self = [super initWithWindowNibName:@"Employee"]) {
_employee = [employee retain];
}
return self;
}
- (void)dealloc {
[_employee release];
[super dealloc];
}
- (void)windowDidLoad {
// populates the window's controls, not necessary if using bindings
[nameField setStringValue:self.employee.name];
[titleField setStringValue:self.employee.title];
}
@end
Você verá que estou usando a variável de instância que faz referência a um Employee
diretamente no meu -init
e -dealloc
método, enquanto estou usando a propriedade em outros métodos.Geralmente, esse é um bom padrão com propriedades:Toque apenas na variável de instância subjacente para uma propriedade em inicializadores, em -dealloc
, e no getter e setter da propriedade.
Outras dicas
Sigo o conselho de Chris Hanson em relação ao prefixo ivar de sublinhado, embora admita que também uso sublinhado para IBOutlets.No entanto, recentemente comecei a mover meu IBOutlet
declarações ao @property
linha, conforme Sugestão do @mmalc.A vantagem é que todos os meus ivars agora têm um sublinhado e os setters KVC padrão são chamados (ou seja, setNameField:
).Além disso, os nomes dos pontos de venda não possuem sublinhados no Interface Builder.
@interface EmployeeWindowController : NSWindowController {
@private
// model object this window is presenting
Employee *_employee;
// outlets connected to views in the window
NSTextField *_nameField;
NSTextField *_titleField;
}
- (id)initWithEmployee:(Employee *)employee;
@property(readwrite, retain) Employee *employee;
@property(nonatomic, retain) IBOutlet NSTextField *nameField;
@property(nonatomic, retain) IBOutlet NSTextField *titleField;
@end
Você pode usar o prefixo underbar em seus ivars e ainda usar o nome não underbar para suas propriedades.Para acessadores sintetizados, basta fazer isto:
@synthesize foo = _foo;
Isso diz ao compilador para sintetizar a propriedade foo usando the_foo ivar.
Se você escrever seus próprios acessadores, basta usar o ivar underbar em sua implementação e manter o nome do método não underbar.
Pessoalmente, sigo as convenções de nomenclatura do Cocoa, usando camel-casing para funções e variáveis, e camel-casing em maiúscula para nomes de objetos (sem o NS inicial, é claro).
Acho que o prefixo de tipo torna o código mais opaco para quem não o escreveu (já que todos invariavelmente usam prefixos diferentes) e, em um IDE moderno, não é tão difícil descobrir o tipo de algo.
Com a introdução das propriedades, não vejo necessidade de prefixar "_" nas variáveis de instância da classe.Você pode definir uma regra simples (descrita em seu arquivo de cabeçalho) de que quaisquer variáveis a serem acessadas externamente à classe devem ser acessadas por meio da propriedade ou usando métodos personalizados na classe para afetar os valores.Isso para mim parece muito mais limpo do que ter nomes com "_" colados na frente deles.Ele também encapsula adequadamente os valores para que você possa controlar como eles são alterados.
Não gosto de usar sublinhados como prefixos para quaisquer identificadores, porque C e C++ reservam certos prefixos de sublinhado para uso pela implementação.
Acho que usar "self.variable" é feio.
Em geral, eu uso identificadores simples (ou seja, sem prefixos nem sufixos) para variáveis de instância.Se sua classe é tão complicada que você não consegue se lembrar das variáveis de instância, você está em apuros.Então, para o seu exemplo, eu usaria "rect" como o nome da variável de instância e "newRect" ou "aRect" como o nome do parâmetro.
André:Na verdade, existem muitos desenvolvedores do Cocoa que não usam prefixos de variáveis de instância.Também é extremamente comum no mundo Smalltalk (na verdade, eu diria que é quase inédito em Smalltalk usar prefixos em variáveis de instância).
Prefixos em variáveis de instância sempre me pareceram um C++-ismo que foi trazido para Java e depois para C#.Como o mundo Objective-C era em grande parte paralelo ao mundo C++, enquanto os mundos Java e C# são sucessores dele, isso explicaria a diferença "cultural" que você pode ver entre os diferentes conjuntos de desenvolvedores.
Meu estilo é híbrido e realmente um resquício da época do PowerPlant:
Os prefixos mais úteis que uso são "in" e "out" para parâmetros de função/método.Isso ajuda você a saber rapidamente para que servem os parâmetros e realmente ajuda a evitar conflitos entre parâmetros de método e variáveis de instância (quantas vezes você viu o parâmetro "tabela" entrar em conflito com uma variável de instância de mesmo nome).Por exemplo.:
- (void)doSomethingWith:(id)inSomeObject error:(NSError **)outError;
Então eu uso o nome simples para variáveis de instância e nomes de propriedades:
Então eu uso "the" como prefixo para variáveis locais:a tabela, o URL, etc.Novamente, isso ajuda a diferenciar entre variáveis locais e de instância.
Depois, seguindo o estilo do PowerPlant, uso vários outros prefixos:k para constantes, E para enumerações, g para globais e s para estática.
Eu uso esse estilo há cerca de 12 anos.
Embora eu adore usar o prefixo de sublinhado para ivars, detesto escrever @synthesize
linhas por causa de toda a duplicação (não é muito SECO).Criei uma macro para ajudar a fazer isso e reduzir a duplicação de código.Assim, em vez de:
@synthesize employee = _employee;
Eu escrevo isto:
ddsynthesize(employee);
É uma macro simples usando colagem de token para adicionar um sublinhado no lado direito:
#define ddsynthesize(_X_) @synthesize _X_ = _##_X_
A única desvantagem é que isso confundirá a ferramenta de refatoração do Xcode e não será renomeada se você renomear a propriedade por refatoração.
Junto com o que foi dito aqui, não deixe de ler a documentação do Cocoa sobre nomenclatura compatível com observação de valores-chave.Seguir rigorosamente esse padrão o ajudará muito no longo prazo.