Qual é a diferença entre ivars e propriedades em Objective-C?

Qual é a diferença semântica entre essas três maneiras de usar ivars e propriedades no objective-c?

1

@class MyOtherObject; @interface MyObject { } @property (nonatomic, retain) MyOtherObject *otherObj; 

2

 #import "MyOtherObject.h" @interface MyObject { MyOtherObject *otherObj; } @property (nonatomic, retain) MyOtherObject *otherObj; 

3

  #import "MyOtherObject.h" @interface MyObject { MyOtherObject *otherObj; } 

O número 1 difere dos outros dois por encaminhar declarando a class MyOtherObject para minimizar a quantidade de código visto pelo compilador e vinculador e também potencialmente evitar referências circulares. Se você fizer dessa maneira, lembre-se de colocar o #import no arquivo .m.

Ao declarar um arquivo @property, (e correspondente @synthesize no .m), você gera automaticamente methods de access com a semântica de memory tratada como você especifica. A regra básica para a maioria dos objects é Retain, mas NSStrings, por exemplo, deve usar Copy. Considerando que os Singletons e os Delegados devem geralmente usar Assign. Os acessadores de escrita à mão são entediantes e propensos a erros, o que economiza muitos erros de digitação e estupidez.

Além disso, declarar uma propriedade sintetizada permite chamar um método de access usando notação de ponto como esta:

 self.otherObj = someOtherNewObject; // set it MyOtherObject *thingee = self.otherObj; // get it 

Em vez do caminho normal de passagem de mensagens:

 [self setOtherObject:someOtherNewObject]; // set it MyOtherObject *thingee = [self otherObj]; // get it 

Nos bastidores você está realmente chamando um método que se parece com isso:

 - (void) setOtherObj:(MyOtherObject *)anOtherObject { if (otherObject == anOtherObject) { return; } MyOtherObject *oldOtherObject = otherObject; // keep a reference to the old value for a second otherObject = [anOtherObject retain]; // put the new value in [oldOtherObject release]; // let go of the old object } // set it 

…ou isto

 - (MyOtherObject *) otherObject { return otherObject; } // get it 

Dor total na bunda, certo. Agora faça isso para cada ivar na class. Se você não fizer exatamente certo, você receberá um memory leaks. Melhor deixar apenas o compilador fazer o trabalho.

Eu vejo que o número 1 não tem um ivar. Supondo que não seja um erro de digitação, tudo bem, porque as diretivas @property / @synthesize também declaram um ivar para você, nos bastidores. Eu acredito que isso é novo para o Mac OS X – Snow Leopard e iOS4.

O número 3 não tem esses acessadores gerados, portanto você deve escrevê-los você mesmo. Se você quiser que seus methods de access tenham efeitos colaterais, faça sua dança de gerenciamento de memory padrão, como mostrado acima, e faça o trabalho que precisar, dentro do método do acessador. Se você sintetizar uma propriedade e também escrever sua própria , sua versão terá prioridade.

Eu cobri tudo?

Nos velhos tempos você tinha ivars, e se você quisesse deixar alguma outra class configurada ou lê-los então você tinha que definir um getter (ie, -(NSString *)foo) e um setter (ie, -(void)setFoo:(NSString *)aFoo; ).

Que propriedades lhe dão é setter e getter de graça (quase!) Junto com um ivar. Então, quando você define uma propriedade agora, você pode definir a atomicidade (você quer permitir múltiplas ações de configuração de múltiplos threads, por exemplo), assim como designar / reter / copiar semântica (isto é, se o setter copiar o novo valor ou apenas salve o valor atual – importante se outra class estiver tentando definir sua propriedade de string com uma string mutável que pode ser alterada posteriormente).

Isto é o que @synthesize faz. Muitas pessoas deixam o mesmo nome, mas você pode alterá-lo quando você escreve sua instrução de síntese (isto é, @synthesize foo=_foo; significa fazer um ivar chamado _foo para a propriedade foo , então se você quiser ler ou escrever esta propriedade e você não usa self.foo , você terá que usar _foo = ... – apenas ajuda a pegar referências diretas ao ivar se você quiser apenas passar pelo setter e pelo getter).

A partir do Xcode 4.6, você não precisa usar a instrução @synthesize – o compilador fará isso automaticamente e por padrão irá pré-append o nome do ivar com _ .