2009-10-01 11 views
5

Sto lavorando attraverso il capitolo "Codifica valore chiave" in "Programmazione per Mac OS X". Ho costruito un'interfaccia con un cursore e un'etichetta, entrambi legati a fido, un int. Se imposto la proprietà per fido a sola lettura, lo spostamento del cursore fa sì che l'etichetta cambi il suo valore. Avevo pensato che avrei avuto una sorta di errore per questo. Se la proprietà è in sola lettura, come mai il cursore può ancora scrivere nella proprietà? Pensavo che non avrebbe creato nessun setter e che KVC non avrebbe funzionato. Grazie.Perché una proprietà readonly consente ancora la scrittura con KVC

Ecco il codice che sto utilizzando:

#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 text http://idisk.me.com/nevan/Public/Pictures/Skitch/Window-20091001-174352.png

risposta

16

AppController.h:

@interface AppController : NSObject 
{ 
     int fido; 
} 

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

importazione "AppController.h"

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

A questo punto, hai dichiarato che AppController ha un metodo -fido e hai sintetizzato quel metodo. Non esiste il metodo -setFido:. Quindi, perché il seguente "lavoro"?

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

(BTW: ho fissato il vostro -init per implementare il modello corretto)

Questo funziona perché KVC segue un euristica per impostare o ottenere il valore. La chiamata a -setValue:forKey: cerca prima -setFoo:. Se non viene trovato, cerca la variabile di istanza foo e imposta direttamente.

Si noti che se si modifica la variabile di istanza fido al _fido, il set funzionerà, ma il valueForKey tornerà 0 come viene chiamato il metodo sintetizzato (dato che sono a 64 bit, il @synthesize sintetizza una variabile fido un'istanza Confondendo, lo so.).

Se si dovesse modificare il nome della vostra ivar su bar e quindi utilizzare @synthesize foo=bar;, il codice non funzionerà in fase di esecuzione.

vedrete:

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 
+9

Puoi anche usare + (BOOL) accessInstanceVariablesDirectly {return NO; } per eliminare questo comportamento KVC – sbooth

+0

Un buon punto e una buona abitudine per entrare. Grazie! – bbum

+0

Ottima risposta, grazie. Il motivo per cui ho fatto questa domanda è che uno dei punti principali del capitolo è che KVC usa i setter e i getter. Avevo pensato che fosse l'unico modo in cui lavoravano. Lo stile di init è lo stile che usa nel libro. Dice che le classi che sottoclasse non restituiscono mai nulla, quindi lascia il controllo per semplicità. –

1

Avere sola lettura proprietà significa che compilatore non genererà si setter per la proprietà. È ancora legale scriverlo tramite KVO/KVC.

+1

che non è ciò che sta accadendo qui. – bbum

1

Le direttive del compilatore @property e @synthesize sono solo modi in breve tempo per creare i metodi per ottenere e impostare la variabile in questione.

Il metodo di impostazione creato è denominato setFido: e il metodo getter è denominato solo fido.

Quando si specifica readonly, credo semplicemente che dice al compilatore di non creare il metodo setter, ma solo il getter. Non pone alcun tipo di barriera nel modo di impostare la variabile con altri mezzi.

(Speranza ho tutto quel diritto Buona fortuna.!)

+0

Più o meno corretto.Vedi la mia risposta per specifiche. – bbum

Problemi correlati