2009-10-01 7 views
5

「Mac OS X用プログラミング」の「キー値コーディング」の章で作業しています。私はスライダとラベルを持つインターフェイスを構築しました。どちらもfido、intにバインドされています。 fidoのプロパティを読み取り専用に設定しても、スライダを動かすと、ラベルの値が変更されます。私はこれに対して何らかのエラーを取ると思っていた。プロパティが読み込み専用の場合、スライダーはどのようにプロパティに書き込むことができますか?私はそれはセッターが作成されていないだろうと思って、KVCは動作しませんでした。ありがとう。readonlyプロパティでKVCでの書き込みが可能になるのはなぜですか?

ここで私が使用しているコードです:

#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

答えて

16

AppController.h:

@interface AppController : NSObject 
{ 
     int fido; 
} 

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

輸入 "AppController.h" この時点で

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

、 AppControllerに-fidoメソッドがあり、そのメソッドを合成したと宣言しました。方法はありません。-setFido:だから、なぜ次の「働く」のは?

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

:KVCは値を設定または取得するヒューリスティックを以下のため、この作品

を(ところで、私は正しいパターンを実装するためにあなたの-initを固定)。 -setValue:forKey:への呼び出しは、最初に-setFoo:を探します。見つからなければ、インスタンス変数fooを探し、それを直接設定します。あなたはfido_fidoへの変数のインスタンスを変更した場合、セットは動作しますが、私は64ビットの上だので、それは(合成されたメソッドを呼び出すようvalueForKeyは0を返すこと

注意、@synthesizeはfidoインスタンス変数を合成します混乱して、私は知っている)。

イヴァールの名前をbarに変更してから@synthesize foo=bar;を使用すると、実行時にコードが失敗します。

あなたはわかります

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

また、+(BOOL)accessInstanceVariablesDirectly {return NO; }このKVCの振る舞いを排除するには – sbooth

+0

良い点といい習慣があります。ありがとう! – bbum

+0

偉大な答え、ありがとう。私がこの質問をしてきたのは、この章の主なポイントの1つは、KVCがセッターとゲッターを使用していることでした。私はそれが彼らが働く唯一の方法だと思っていた。 initスタイルは、彼が本で使用するスタイルです。彼は、サブクラスのクラスは決して無限に戻ることはないので、簡単にするためにチェックを外します。 –

1

を読み取り専用プロパティを持つには、コンパイラは、あなたがそのプロパティのsetter生成しないことを意味します。 KVO/KVC経由で書き込むことはまだ合法です。

+1

ここで何が起こっているのかされていないこと。 – bbum

1

コンパイラ指令@propertyおよび@synthesizeは、問題の変数を取得および設定するためのメソッドを作成するための簡単な方法です。

作成されるセッターメソッドの名前はsetFido:で、ゲッターメソッドの名前はfidoです。

readonlyを指定すると、コンパイラにsetterメソッドを作成せず、getterのみを作成するように指示すると考えられます。それは、他の手段で変数を設定する方法においていかなる種類の障壁も置かない。

(私はすべてその権利を持っている希望グッドラック!)

+0

多かれ少なかれ正しい。詳細については私の答えを見てください。 – bbum

関連する問題