Pergunta

Eu estou trabalhando através do "Valor Key Codificação" capítulo "de programação para Mac OS X". Eu construí uma interface com um controle deslizante e uma etiqueta, tanto obrigado a fido, um int. Se eu definir a propriedade para Fido para somente leitura, movendo o cursor ainda faz com que o rótulo para mudá-lo de valor. Eu tinha assumido que eu obter algum tipo de erro para isso. Se a propriedade é somente leitura, como é que o controle deslizante ainda pode escrever para a propriedade? Eu pensei que não teria setters criado, e KVC não iria funcionar. Obrigado.

Aqui está o código que estou usando:

#import <Cocoa/Cocoa.h>

@interface AppController : NSObject
{
    int fido;
}

@property (readonly, assign) int fido;

@end

#import "AppController.h"

@implementation AppController

@synthesize fido;

- (id)init
{
    [super init];
    [self setValue:[NSNumber numberWithInt:5] forKey:@"fido"];
    NSNumber *n = [self valueForKey:@"fido"];
    NSLog(@"fido = %@", n);
    return self;
}
@end

alt texto http://idisk.me.com/nevan/Public /Pictures/Skitch/Window-20091001-174352.png

Foi útil?

Solução

AppController.h:

@interface AppController : NSObject
{
        int fido;
}

@property (readonly, assign) int fido;
@end

importação "AppController.h"

@implementation AppController
@synthesize fido;
...
@end

Neste ponto, você declarou que AppController tem um método -fido e você sintetizaram esse método. Não há nenhum método -setFido:. Então, por que faz o seguinte "trabalho"?

- (id)init
{
        if (self=[super init]) {
            [self setValue:[NSNumber numberWithInt:5] forKey:@"fido"];
            NSNumber *n = [self valueForKey:@"fido"];
            NSLog(@"fido = %@", n);
        }
        return self;
}

(BTW: Eu fixo o seu -init para implementar o padrão correto)

Isso funciona porque KVC segue um heurística para definir ou obter o valor. A chamada para -setValue:forKey: primeiro procura -setFoo:. Se não for encontrado, ele então olha para o foo variável de instância e define-lo diretamente.

Note que se você alterar a variável de instância fido para _fido, o conjunto vai funcionar, mas o valueForKey irá retornar 0 como ele chama o método sintetizado (desde que eu estou em 64 bit, o @synthesize sintetiza uma variável de instância fido. confundindo, eu sei.).

Se você fosse para mudar o nome do seu ivar para bar e depois usar @synthesize foo=bar;, o código seria falhar em tempo de execução.

Você verá:

2009-10-01 08:59:58.081 dfkjdfkjfjkfd[24099:903] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<AppController 0x20000e700> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key fido.'
*** Call stack at first throw:
(
    0   CoreFoundation                      0x00007fff85b055a4 __exceptionPreprocess + 180
    1   libobjc.A.dylib                     0x00007fff85c5a0f3 objc_exception_throw + 45
    2   CoreFoundation                      0x00007fff85b5caf9 -[NSException raise] + 9
    3   Foundation                          0x00007fff814e14f5 -[NSObject(NSKeyValueCoding) setValue:forKey:] + 434
(
    0   CoreFoundation                      0x00007fff85b055a4 __exceptionPreprocess + 180
    1   libobjc.A.dylib                     0x00007fff85c5a0f3 objc_exception_throw + 45
    2   CoreFoundation                      0x00007fff85b5caf9 -[NSException raise] + 9
    3   Foundation                          0x00007fff814e14f5 -[NSObject(NSKeyValueCoding) setValue:forKey:] + 434
    4   dfkjdfkjfjkfd                       0x0000000100000d96 -[AppController init] + 130

Outras dicas

Tendo meios propriedade somente leitura que compilador não irá gerar você setter para essa propriedade. Ainda é legal para escrever a ele através de KVO / KVC.

As diretivas de compilador @property e @synthesize são apenas formas de taquigrafia para criar os métodos para obter e definir a variável em questão.

O método setter criado é nomeado setFido:, eo método getter é apenas fido nomeado.

Quando você especifica somente leitura, acredito que simplesmente diz o compilador não para criar o método setter, mas apenas o getter. Ele não colocar qualquer tipo de barreira na forma de definir a variável por outros meios.

(Hope Eu tenho todo esse direito. Boa sorte!)

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