プロパティーやインスタンス変数の値を文字列で指定して取得する (KVC) : Objective-C プログラミング

PROGRAM


プロパティーやインスタンス変数の値を文字列で指定して取得する (KVC)

KVC を使ってプロパティーを読み書きする

Objective-C では KVC という機能を使うことで、クラスに実装されているプロパティーの名前を文字列で指定して読み書きできるようになっています。

たとえば、プロパティーが "@property (readwrite,strong) NSString *name" で定義されているクラスがあったとします。

@interface EzObject : NSObject

@property (readwrite,strong) NSString *name;

@end

このとき、このクラスのインスタンス "object" に対して "-valueForKey:" メソッドと "-setValue:forKey:" メソッドを使って、次のように "name" プロパティーを読み書きできます。

// プロパティーの値を読み込む

NSString *value = [object valueForKey:@"name"];

 

// プロパティーに値 (value) を書き込む

[object setValue:value forKey:@"name"];

KVC を使ってインスタンス変数を読み書きする

セッターやゲッターが用意されていないインスタンス変数も KVC を使って読み書きできます。

たとえば、インスタンス変数 "NSString *_name" が定義されたクラスがあったとします。

@interface EzObject : NSObject

{

NSString *_name;

}

@end

このようなとき、このクラスのインスタンス "object" に対して、先ほど紹介した "name" プロパティーがあったときと全く同じ方法で、このインスタンス変数 "_name" を読み書きできます。

// インスタンス変数 "_name" の値を読み込む

NSString *value = [object valueForKey:@"name"];

 

// インスタンス変数 "_name" に値 (value) を書き込む

[object setValue:value forKey:@"name"];

ここで指定する名前は、インスタンス変数の名前が "_" で始まる場合は、それを取り除いた名前になります。インスタンス変数の名前が "_" で始まらない場合には、そのままの名前を指定することで、値を読み書きできます。

 

プロパティーやインスタンス変数がプリミティブ型の場合

プロパティーやインスタンス変数が数値型の場合

プロパティーやインスタンス変数のデータ型が NSInteger や int や double などといった数値型の場合は、それらは NSNumber 型として扱われます。

たとえば、次のように float 型のプロパティー "coefficient" があったとします。

@interface EzObject : NSObject

@property (readwrite) float coefficient;

@end

このようなとき、KVC では NSNumber 型を使って "-valueForKey:" メソッドと "-setValue:forKey:" メソッドを介して、プロパティーの値を読み書きすることになります。NSNumber 型とプリミティブ型との変換は自動的に行われます。

NSNumber *numberValue;

float floatValue = 10.2;

 

// プロパティー "coefficient" の値を読み込む

numberValue = [object valueForKey:@"coefficient"];

 

// プロパティー "coefficient" に値 (floatValue) を書き込む

[object setValue:@(floatValue) forKey:@"coefficient"];

プロパティーやインスタンス変数がポインター型の場合

プロパティーやインスタンス変数で扱うデータ型が char* などのプリミティブ型のポインターの場合、KVC でそれらの値を扱うことはできないようです。

そのような場合に "-setValue:forKey:" メソッドで値を書き込もうとすると、次のようなメッセージとともに NSUnknownKeyException 例外が発生します。

this class is not key value coding-compliant for the key $(PROPERTY_NAME)

ちなみに C 言語のポインターとは表記が似ていても、Objective-C の NSArray* 型などのいわゆる id 型の場合は、問題なく利用できます。

もし、配列を扱うためにプリミティブ型のポインターを使用している場合は、NSArray 型を使って値を扱うようにすると良いでしょう。このとき、プリミティブ型は NSArray で直接持つことはできないので、それぞれをさらに NSNumber 型にして持つ必要があります。

 

KVC で値に nil が指定されたときに既定値を設定する

KVC でプリミティブ型のプロパティーやインスタンス変数に nil を設定しようとすると、既定では次のようなメッセージとともに NSInvalidArgumentException 例外が発生します。

could not set nil as the value for the key $(PROPERTY_NAME)

プリミティブ型の値として nil が指定された場合に、既定値などの代わりの値を設定したい場合には、KVC で値を読み書きする対象のクラスに "-setNilValueForKey:" メソッドを実装して、そこで任意の値を設定するようにします。

- (void)setNilValueForKey:(NSString*)key

{

if ([key isEqualToString:@"coefficient"])

{

// 指定されたキーが "coefficient" の場合に既定値を設定します。

self.coefficient = 1.0;

}

else

{

// 代わりの値を想定していないキーは、親クラスの setNilValueForKey: に処理を委ねます。

[super setNilValueForKey:key];

}

}

NSString 型などの Objective-C オブジェクト型の場合には nil を問題なく設定できますが、そのときにはこの "-setNilValueForKey:" は呼び出されません。あくまでも KVC でプリミティブ型を対象に nil を設定しようとしたときにだけ呼び出されます。

[ もどる ]