As propriedades declaradas requerem uma variável de instância correspondente?

101

As propriedades em Objective-C 2.0 requerem que uma variável de instância correspondente seja declarada? Por exemplo, estou acostumado a fazer algo assim:

MyObject.h

@interface MyObject : NSObject {
NSString *name;
}
@property (nonatomic, retain) NSString *name;
@end

MyObject.m

@implementation
@synthesize name;
@end

No entanto, e se eu fizesse isso em vez disso:

MyObject.h

@interface MyObject : NSObject {
}
@property (nonatomic, retain) NSString *name;
@end

Isso ainda é válido? E é de alguma forma diferente do meu exemplo anterior?

Indragie
fonte
Por que o segundo 'MyObject.h' em negrito não está 'MyObject.m'?
Ríomhaire

Respostas:

93

Se você estiver usando o Modern Objective-C Runtime (iOS 3.x ou superior, ou Snow Leopard de 64 bits ou superior), não necessário definir ivars para suas propriedades em casos como este.

Quando você @synthesizea propriedade, o ivar na verdade será sintetizado também para você. Isso contorna o cenário "frágil-ivar". Você pode ler mais sobre isso no Cocoa with Love

Jbrennan
fonte
71

Em sua interface, você pode declarar formalmente uma variável de instância entre as chaves, ou por meio de @propertyfora das chaves, ou ambos. De qualquer forma, eles se tornam atributos da classe. A diferença é que, se você declarar @property, poderá implementar o using @synthesize, que codifica automaticamente seu getter / setter para você. O setter autocodificador inicializa inteiros e flutua para zero, por exemplo. SE você declarar uma variável de instância e NÃO especificar uma correspondente @property, não poderá usar @synthesizee deverá escrever seu próprio getter / setter.

Você sempre pode substituir o getter / setter codificado automaticamente especificando o seu próprio. Isso geralmente é feito com a managedObjectContextpropriedade que é carregada lentamente. Assim, você declara seu managedObjectContextcomo uma propriedade, mas também escreve um-(NSManagedObjectContext *)managedObjectContext método. Lembre-se de que um método, que tem o mesmo nome de uma variável / propriedade de instância, é o método "getter".

O @propertymétodo de declaração também permite outras opções, como retaine readonly, que o método de declaração de variável de instância não permite. Basicamente, ivaré a maneira antiga, e @propertyestende-a e torna-a mais sofisticada / fácil. Você pode se referir a qualquer um deles usando o self. prefixo, ou não, não importa, desde que o nome seja único para aquela classe. Caso contrário, se sua superclasse tiver o mesmo nome de uma propriedade que você, você terá que dizer self.name ou super.name para especificar de qual nome está falando.

Assim, você verá cada vez menos pessoas declarando ivars entre colchetes e, em vez disso, passar a apenas especificar @propertye depois fazer @synthesize. Você não pode fazer @synthesizeem sua implementação sem um correspondente @property. O Sintetizador só sabe que tipo de atributo é a partir da @propertyespecificação. A instrução de síntese também permite renomear propriedades, para que você possa se referir a uma propriedade por um nome (abreviação) dentro do seu código, mas fora do arquivo .h use o nome completo. No entanto, com o autocomplete muito legal que o XCode tem agora, isso é menos uma vantagem, mas ainda está lá.

Espero que isso ajude a esclarecer toda a confusão e desinformação que está circulando por aí.

PapaSmurf
fonte
Hoje em dia não é obrigatório escrever @synthesize. Então, como essa resposta é válida nesse caso!
raaz
Você não TEM QUE declarar <code> @property ... @ synthesize </code>. O uso de synthesize evita que você tenha que escrever um getter / setter em sua implementação. Se você não sintetizar, você deve lançar seu próprio getter / setter
PapaSmurf
2
@PapaSmurf Isso está incorreto. Você pode usar @property, e não usar @synthesizee não implementá-los sozinho. O compilador será automático synthesizepara você, sem ter que escrever mais isso.
jbrennan
8

funciona dos dois modos, mas se você não os declarar entre chaves, você não verá seus valores no depurador no xcode.

rickm
fonte
3

Da documentação:

Em geral, o comportamento das propriedades é idêntico em tempos de execução modernos e legados (consulte “Versões e plataformas de tempo de execução” no Objective-C Runtime Programming Guide). Há uma diferença fundamental: o tempo de execução moderno oferece suporte à síntese de variáveis ​​de instância, enquanto o tempo de execução legado não.

Para que @synthesize funcione no tempo de execução legado, você deve 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. Com o tempo de execução moderno, se você não fornecer uma variável de instância, o compilador adiciona uma para você.

Charlie Elliott
fonte
3

Se você estiver usando o XCode 4.4 ou posterior, ele gerará um código de síntese de variáveis ​​de instância para você.

Você apenas tem que declarar propriedades como abaixo; ele irá gerar código de síntese e código de declaração de variável de instância para você.

@property (nonatomic, strong) NSString *name;

ele irá gerar código de síntese como

@synthesize name = _name;

e você pode acessar a variável de instância usando _name, é semelhante a declarar

NSString* _name

mas se você declarar propriedade somente leitura, como

@property (nonatomic, strong, readonly) NSString *name;

vai gerar código

@synthesize name;

ou

@synthesize name = name; 

Portanto, você deve acessar o nome da variável instantânea sem o prefixo "_" de qualquer maneira que possa escrever seu próprio código de síntese, então o compilador irá gerar o código para você. você pode escrever

@synthesize name = _name;
Shafraz Buhary
fonte
1

A Linguagem de Programação Objective-C: Diretivas de Implementação de Propriedade

Existem diferenças no comportamento de síntese do acessador que dependem do tempo de execução (consulte também “Diferença de tempo de execução”):

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

  • Para os tempos de execução modernos (consulte “Versões e plataformas de tempo de execução” em Objective-C Runtime Programming Guide), as variáveis ​​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.

Nate
fonte