Propriedade vs. variável de instância

Estou tentando entender como as estratégias que algumas pessoas usam para distinguir a instância vars versus propriedades. Um padrão comum é o seguinte:

@interface MyClass : NSObject { NSString *_myVar; } @property (nonatomic, retain) NSString *myVar; @end @implementation MyClass @synthesize myVar = _myVar; 

Agora, eu pensei que toda a premissa por trás dessa estratégia é para que se possa facilmente distinguir a diferença entre um ivar e uma propriedade. Então, se eu quiser usar o gerenciamento de memory herdado por uma propriedade sintetizada, usaria algo como:

 myVar = @"Foo"; 

O outro caminho seria referenciá-lo por si mesmo [ivar / propriedade aqui].

O problema com o uso da estratégia @synthesize myVar = _myVar, é que imaginei que escrever código como:

 myVar = some_other_object; // doesn't work. 

O compilador reclama que myVar não é declarado. Por que esse é o caso?

Obrigado.

Propriedades são apenas setters e getters para ivars e devem (quase) sempre ser usadas ao invés de access direto.

 @interface APerson : NSObject { // NSString *_name; // necessary for legacy runtime } @property(readwrite) NSString *name; @end @implementation APerson @synthesize name; // use name = _name for legacy runtime @end 

@synthesize cria neste caso os dois methods (não 100% precisos):

 - (NSString *)name { return [[_name copy] autorelease]; } - (void)setName:(NSString *)value { [value retain]; [_name release]; _name = value; } 

Agora é fácil distinguir entre ivars e getters / setters. Os acessadores conseguiram o self. prefixo. Você não deve acessar as variables ​​diretamente de qualquer maneira.


Seu código de amostra não funciona como deveria:

 _myVar = some_other_object; // _myVar is the ivar, not myVar. self.myVar = some_other_object; // works too, uses the accessors 

Uma propriedade sintetizada chamada prop é representada por dois methods prop (retornando o valor atual da propriedade) e setProp: (configurando um novo valor para prop).

A syntax self.prop é o açúcar sintático para chamar um desses acessadores. No seu exemplo, você pode fazer qualquer um dos seguintes para definir a propriedade myVar :

 self.myVar = @"foo"; // handles retain/release as specified by your property declaration [self setMyVar: @"foo"]; // handle retain/release _myVar = @"Foo"; // does not release old object and does not retain the new object 

Para acessar as propriedades, use self.propname . Para acessar variables ​​de instância, use apenas o nome da variável de instância.

O problema com o uso da estratégia @synthesize myVar = _myVar, é que imaginei que escrever código como:

 myVar = some_other_object; // doesn't work. 

O compilador reclama que myVar não é declarado. Por que esse é o caso?

Porque a variável myVar não é declarada.

Essa declaração usa a syntax para acessar uma variável, seja uma variável de instância ou outro tipo. Como rincewind disse, para acessar uma propriedade, você deve usar a syntax de access à propriedade ( self.myVar = someOtherObject ) ou uma mensagem explícita para o método do acessador ( [self setMyVar:someOtherObject] ).

Caso contrário, você está tentando acessar uma variável e, como você não tem uma variável chamada myVar , você está tentando acessar uma variável que não existe.

Em geral, nomeio minhas propriedades da mesma forma que minhas variables ​​de instância; esta é a suposição padrão que a syntax @property faz. Se você acha que está lutando contra os padrões, está fazendo errado (ou o seu framework sux, o que não é o caso de Cocoa / Cocoa-touch na minha opinião).

O erro do compilador que você está obtendo é porque o uso da propriedade sempre tem que ter uma referência de object, mesmo dentro da sua própria implementação de class:

 self.stuff = @"foo"; // property setter [stuff release]; // instance variable stuff = @"bar"; // instance variable return self.stuff; // property getter 

Eu sei que muitos programadores do Cocoa discordam, mas eu acho que é uma prática ruim usar propriedades dentro da sua implementação de class. Eu prefiro ver algo assim:

 -(void) someActionWithStuff: (NSString*) theStuff { // do something [stuff release]; stuff = [theStuff copy]; // do something else } 

do que isso:

 -(void) someActionWithStuff: (NSString*) theStuff { // do something self.stuff = theStuff; // do something else } 

Eu prefiro fazer gerenciamento de memory da forma mais explícita possível. Mas mesmo se você não concordar, usar o formulário self.stuff irá indicar em qualquer programador experiente de Objective-C que você está chamando uma propriedade em vez de acessar uma variável de instância. É um ponto sutil que é fácil para os iniciantes encobrirem, mas depois de trabalhar com o Objective-C 2.0 por um tempo, está bem claro.

Don,

De acordo com as “regras”, você deve chamar Liberar para cada Cópia, Alocar e Reter. Então, por que você está ligando para o Release? Isso é presumir que foi criado usando Alloc, Copy ou Retain?

Isso traz outra questão: é prejudicial chamar Liberar uma referência a um object se ele já foi lançado?

Já que a Apple reserva o prefixo _ para si mesmo, e como prefiro torná-lo mais óbvio quando estou usando o setter e quando estou usando o ivar, adotei a prática de usar um prefixo de i_ em meus ivars, por exemplo :

 @interface MyClass : NSObject { NSString *i_myVar; } @property (nonatomic, retain) NSString *myVar; @synthesize myVar = i_myVar; i_myVar = [input retain]; self.myVar = anotherInput; [i_myVar release] 

Como é muito importante saber quando você está usando o setter e quando você está usando o ivar, eu acho que o nome explicitamente diferente é mais seguro.

Na sua pergunta, deveria ser:

 self.myVar = @"Foo"; // with setter, equivalent to [self setMyVar:@"Foo"] 

e

 _myVar = some_other_object; // direct ivar access - no memory management! 

Lembre-se que você não deve usar setters / getters no init / dealloc, então você precisa fazer o seu access ivar direto (e cuidadoso gerenciamento da memory) nesses methods.

o que há de errado com simplesmente usando

 @interface MyClass : NSObject @property NSString *prop; @end 

nonatomic e reter não são necessários, reter é o padrão, e atômico / não atômico não é importante a menos que o XCode avise com um aviso.

NÃO é necessário declarar o iVar, um será criado para você chamado _prop, se você realmente quiser usar um (eu não vejo por que ser honesto)

@synthesize NÃO é obrigatório.

quando (e você deveria) usar o ARC, você não precisa se preocupar em reter e liberar.

mantenha simples !

além disso, se você tem um método como este

 - (void)aMethod:(NSString*)string { self.prop = string; // shows very clearly that we are setting the property of our object _aName = string; // what is _aName ? the _ is a convention, not a real visual help } 

Eu sempre usaria propriedades, mais flexível, mais fácil de ler.