2009-10-01 10 views
5

Pracuję nad rozdziałem "Key Value Coding" w "Programowanie dla Mac OS X". Zbudowałem interfejs z suwakiem i etykietą, obie związane z fido, int. Jeśli ustawię właściwość fido na readonly, przesunięcie suwaka nadal spowoduje, że etykieta zmieni jego wartość. Przyjąłem, że dostanę za to jakiś błąd. Jeśli właściwość jest tylko do odczytu, w jaki sposób suwak może nadal pisać do właściwości? Pomyślałem, że nie byłoby stworzonych seterów, a KVC nie działałby. Dzięki.Dlaczego właściwość readonly nadal pozwala na pisanie z KVC

Oto kod używam:

#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

Odpowiedz

16

AppController.h:

@interface AppController : NSObject 
{ 
     int fido; 
} 

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

import "AppController.h"

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

W tym momencie, zadeklarowałeś, że AppController ma metodę -fido i zsyntetyzowałeś tę metodę. Nie ma metody. Dlaczego więc następująca "praca"?

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

(BTW: Poprawiłem swój -init wdrożenie prawidłowego wzorca)

To działa, ponieważ KVC następuje heurystycznej ustawić lub uzyskać wartość. Połączenie z numerem -setValue:forKey: najpierw szuka -setFoo:. Jeśli nie zostanie znaleziony, szuka zmiennej instancji foo i ustawia ją bezpośrednio.

Należy pamiętać, że w przypadku zmiany zmiennej instancji fido do _fido, zestaw będzie działać, ale valueForKey zwróci 0, gdyż wywołuje metodę zsyntetyzowany (ponieważ jestem na 64 bitów, @synthesize syntetyzuje zmienną fido instancji Mylące, wiem.).

Jeśli zmienisz nazwę swojego ivar na bar, a następnie użyjesz @synthesize foo=bar;, kod zakończy się niepowodzeniem w środowisku wykonawczym.

Zobaczysz:

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

Możesz także użyć + (BOOL) accessInstanceVariablesDirectly {return NO; } aby wyeliminować to zachowanie KVC – sbooth

+0

Dobra uwaga i dobry nawyk, aby się w to wciągnąć. Dzięki! – bbum

+0

Świetna odpowiedź, dzięki. Powodem, dla którego zadałem to pytanie, było to, że jednym z głównych punktów tego rozdziału jest to, że KVC używa ustawiaczy i pobierających. Zakładałem, że to jedyny sposób, w jaki pracowali. Styl init jest stylem, którego używa w książce. Mówi, że klasy, do których zalicza klasy, nigdy nie wracają do zera, więc rezygnuje z kontroli dla uproszczenia. –

1

Mając readonly właściwość oznacza, że ​​kompilator nie wygeneruje Ci setter dla tej właściwości. Nadal można pisać na ten temat za pośrednictwem KVO/KVC.

+1

To nie jest to, co się tu dzieje. – bbum

1

Dyrektywy kompilatora @property i @synthesize to tylko skrótowe sposoby tworzenia metod pobierania i ustawiania danej zmiennej.

Utworzona metoda ustawiająca ma nazwę setFido:, a metoda getter ma nazwę fido.

Kiedy określasz tylko do odczytu, uważam, że po prostu mówi kompilatorowi, aby nie tworzył metody ustawiającej, ale tylko pobierający. Nie stanowi on żadnej bariery w sposobie ustawienia zmiennej w inny sposób.

(Nadzieja Mam wszystko to prawo powodzenia.!)

+0

Mniej więcej poprawne.Zobacz moją odpowiedź dla konkretów. – bbum

Powiązane problemy