Pergunta

Eu tenho vários anos de experiência em Obj-C e Cocoa, mas estou apenas começando agora de volta para ele e os avanços de Obj-C 2.0 etc.

Eu estou tentando obter minha cabeça em torno do tempo de execução moderno e propriedades declarando, etc. Uma coisa que me confunde um pouco é a capacidade no tempo de execução moderna de ter os Ivars criados implicitamente. E, claro, isso implica que em seu código que você deve sempre estar usando self.property para acessar o valor.

No entanto, em init * e dealloc (supondo que você não está usando GC) métodos que deveríamos estar usando o iVar diretamente (no tempo de execução atual).

Assim perguntas são:

  1. Devemos usar os assessores da propriedade no init * e dealloc com Modern Runtime?

  2. Se assim , por isso é diferente? É apenas porque o compilador não pode ver a iVar?

  3. Se eu precisar substituir um assessor, posso ainda acesso que iVar que será definido em tempo de execução ou tenho que definir um iVar real que o tempo de execução, então, usar?

  4. Mais uma vez, se eu posso acessar o Sintetizado iVar , porque eu não posso continuar a fazer isto para init * e métodos dealloc?

Eu li os docs várias vezes, mas eles pareciam um pouco vago sobre tudo isso e eu quero ter certeza que eu entendo bem, a fim de decidir como eu quero continuar a codificação.

Espero que minhas perguntas são claras.


Breve resumo de testar :

  1. Se você não declarar o ivar no legado, compilador é completamente infeliz

  2. Se você usar #ifndef __OBJC2__ torno ivar no legado compilador está feliz e você pode usar tanto Ivar diretamente e como propriedade

  3. Em tempo de execução moderno, você pode deixar o ivar indefinido e acesso como propriedade

  4. Em tempo de execução moderna, tentando acessar Ivar diretamente, sem declaração dá erro durante a compilação

  5. declaração @private de Ivar, é claro, permite acesso direto a ivar, tanto legado e moderno

Não realmente dar uma maneira limpa para ir para a frente agora, não é?

Foi útil?

Solução

Na atual (OS X 10.5 / GCC 4.0.1) compilador, você não pode acessar diretamente os ivars sintetizado-tempo de execução. Greg Parker, um dos engenheiros de tempo de execução OS X colocá-lo este maneira na lista de cacau-dev (12 de Março de 2009):

Você não pode no compilador atual. UMA compilador futuro deve corrigir isso. Usar ivars @private explícitos no entretanto. Um Ivar @private não deve ser considerado parte do contrato - Isso é o que @private meios, aplicadas por avisos do compilador e vinculador erros.

E por que não há uma maneira de declarar explicitamente as variáveis ??de instância no arquivo .m para o novo tempo de execução?

Três razões: (1) há alguns não triviais detalhes do projeto ao trabalho para fora, (2) compilador-engenheiros-hora são limitadas, e (3) são ivars @private geralmente bom o suficiente.

Assim, por agora você deve usar notação de ponto para propriedades de acesso, mesmo em init e dealloc. Isso vai contra a melhor prática de usar ivars diretamente nesses casos, mas não há nenhuma maneira em torno dela. Acho que a facilidade de usar ivars sintetizado-tempo de execução (e os benefícios de desempenho) superam este na maioria dos casos. Onde você precisa acessar o ivar diretamente, você pode usar um ivar @private como Greg Parker sugere (não há nada que o impeça de mistura explicitamente declarado e ivars sintetizado-tempo de execução).

Atualizar Com o OS X 10.6, o tempo de execução de 64 bits não permite acesso direto aos ivars sintetizados via self->ivar.

Outras dicas

Uma vez que as variáveis ??de instância si só pode ser sintetizada no tempo de execução moderna (e deve ser declarado na @interface sob 32 bits ou pré-Leopard), é mais seguro / mais portátil também declarar a ivar

  • Será que devemos usar os assessores da propriedade no init * e dealloc com Modern Runtime?

A minha regra de ouro é "possivelmente" para -init*, e "geralmente não" para -dealloc.

Ao inicializar um objeto, você quer certificar-se de copiar corretamente / reter valores para ivars. A menos que setter da propriedade tem algum efeito colateral que o torna impróprio para a inicialização, definitivamente reutilizar a abstração o estabelecimento oferece.

Quando desalocá um objeto, você quer liberar quaisquer objetos ivar, mas não armazenar novos. Uma maneira fácil de fazer isso é para definir a propriedade a zero (myObject.myIvar = nil), que basicamente chama [myObject setMyIvar:nil]. Desde mensagens para nil são ignorados, não há perigo nisso. No entanto, é um exagero quando [liberação myIvar]; é geralmente tudo que você precisa. Em geral, não use a propriedade (ou diretamente, o setter) em situações onde deallocation deve se comportar de forma diferente do que definir a variável.

Eu posso entender eJames' argumento contra o uso de propriedade acessores em init / dealloc em tudo, mas o outro lado é que se você alterar o comportamento da propriedade (por exemplo, mudança de reter a cópia, ou apenas atribuir sem reter) e Don' t usá-lo em init, ou vice-versa, o comportamento pode ficar fora de sincronia também. Se inicializar e modificando um ivar deve agir da mesma, utilize o acessor propriedade para ambos.

  • Se é assim, por isso é diferente? É apenas porque o compilador não pode ver a Ivar?

Os modernos de tempo de execução lida com o tamanho da classe e layout mais inteligente, razão pela qual você pode alterar o layout dos ivars sem ter que subclasses de recompilação. Ele também é capaz de inferir o nome e tipo do Ivar você quer do nome e tipo da propriedade correspondente. O href="http://developer.apple.com/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/" rel="nofollow noreferrer"> Objective-C 2.0 Guia tem mais informações, mas, novamente, Eu não sei o quão profundamente os detalhes explicados lá.

  • Se eu precisar substituir um assessor, posso ainda acesso que iVar que será definido em tempo de execução ou tenho que definir um iVar real que o tempo de execução, então, usar?

Eu não testei isso, mas eu acredito que você está autorizado a acessar o ivar chamado em código, uma vez que realmente tem que ser criado. Não estou certo se o compilador vai reclamar, mas eu acho que desde que ele vai deixar você sintetizar o ivar sem reclamar, também é inteligente o suficiente para saber sobre o Ivar sintetizados e deixá-lo se referir a ele pelo nome.

  • Uma vez mais, se eu posso acessar o iVar sintetizado, por que não posso continuar a fazer isto para init * e métodos dealloc?

Você deve ser capaz de acessar a propriedade e / ou ivar a qualquer hora depois que a instância foi alocado.

outro SO pergunta com informações semelhantes, mas não é bem um duplicado.

A linha de fundo, a partir da Objectivo-C 2.0 documentação , e citou o Mark Bessey resposta é a seguinte:

Existem diferenças no comportamento que dependem do tempo de execução (ver também “Diferenças de tempo de execução”):

Para os tempos de execução de legado, variáveis ??de instância já deve ser declarado no bloco @ interface. Se uma variável de instância com o mesmo nome e tipo compatível como a propriedade existe, ele é usado, caso contrário, você recebe um erro do compilador.

Para os tempos de execução modernos, variáveis ??de instância são sintetizados conforme necessário. Se uma variável de instância com o mesmo nome já existe, ele é usado.

O meu entendimento é o seguinte:

Você não deve usar os assessores da propriedade em métodos init* e dealloc, pelas mesmas razões que você não deve usá-los em tempo de execução do legado: Ele deixa você abrir a potenciais erros se você mais tarde substituir os métodos de propriedade, e acabar fazendo algo que não deve ser feito em init* ou dealloc.

Você deve ser capaz de tanto sintetizar o ivar e substituir os métodos de propriedade da seguinte forma:

@interface SomeClass
{
}
@property (assign) int someProperty;
@end

@implementation SomeClass
@synthesize someProperty; // this will synthesize the ivar
- (int)someProperty { NSLog(@"getter"); return someProperty; }
- (void)setSomeProperty:(int)newValue
{
    NSLog(@"setter");
    someProperty = newValue;
}
@end

O que me leva a pensar que você seria capaz de acessar o ivar sintetizado em seus init* e dealloc métodos também. A única pegadinha que eu poderia pensar é que a linha @synthesize pode ter que vir antes as definições de seus init* e dealloc métodos no arquivo de origem.

No final, já que ter os ivars declarado na interface ainda funciona, que ainda é a sua aposta mais segura.

Eu estou correndo para o mesmo problema. A maneira que eu estou trabalhando em torno de não ser capaz de acessar as variáveis ??de instância sintetizados é a seguinte:

cabeçalho pública

@interface MyObject:NSObject {
}
@property (retain) id instanceVar;
@property (retain) id customizedVar;
@end

cabeçalho privado / implementação

@interface MyObject()
@property (retain) id storedCustomizedVar;
@end

@implementation MyObject
@synthesize instanceVar, storedCustomizedVar;
@dynamic customizedVar;

- customizedVar {
  if(!self.storedCustomizedVar) {
    id newCustomizedVar;
    //... do something
    self.storedCustomizedVar= newCustomizedVar;
  }
  return self.storedCustomizedVar;
}

- (void) setCustomizedVar:aVar {
  self.storedCustomizedVar=aVar;
}

@end

Não é que elegante, mas pelo menos ele mantém meu arquivo de cabeçalho públicos limpos.

Se você usar KVO você precisa definir customizedVar como chave dependente de storedCustomizedVar.

Eu sou relativamente novo para Obj-C (mas não a programação) e também foram confundidos por este tema.

O aspecto que me preocupa é que parece ser relativamente fácil de inadvertidamente usar o iVar em vez da propriedade. Por exemplo escrita:

myProp = someObject;

em vez de

self.myProp = someObject;

É certo que este é o erro "usuário", mas ainda é parece bastante fácil de fazer acidentalmente em algum código, e para uma propriedade retidos ou atômica poderia presumivelmente levar a problemas.

Idealmente, eu preferiria ser capaz de obter o tempo de execução para aplicar algum padrão para o nome da propriedade ao gerar qualquer iVar. Por exemplo. sempre prefixar-los com "_".

Na prática, no momento eu estou fazendo isso manualmente - declarando explicitamente meus ivars e, deliberadamente, dando-lhes nomes diferentes das propriedades. Eu uso um 'm' prefixo, de estilo antigo por isso, se minha propriedade é "myProp", meu iVar será "mMyProp". Então eu uso @synthesize myProp = mMyProp para associar os dois.

Este é um desajeitado pouco eu admito, e um pouco de digitação extra, mas parece pena para mim ser capaz de disambiguate um pouco mais claramente no código. Claro que ainda pode obtê-lo errado e digite mMyProp = someObject, mas eu estou esperando que o 'm' prefixo vai me alertar para o meu erro.

Ele se sentiria muito melhor se eu pudesse declarar a propriedade e deixar o compilador / runtime fazer o resto, mas quando eu tenho um monte de código meu instinto me diz que eu vou cometer erros que forma, se eu ainda tenho que seguir as regras manuais para o init / dealloc.

Claro que há também uma abundância de outras coisas que eu também pode fazer errado ...

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top