Skip to content

Key-Value Coding Compliant Container Class の作成

2010.07.18

前回は、Key-Value Coding Compliant Container Class の説明とその使い方について説明しました。Key-Value Coding Compliant Container Class は、高い拡張性を持ったクラスで、使い方も簡単でした。そんなクラスを自分で作れたら、嬉しいですね。今回は、Key-Value Coding Compliant Container Class の作り方を説明します。

ここでは、NSInvocationOperation クラスを Key-Value Coding Compliant Container Class に対応させた RLRInvocationOperation クラスを作ってみます。

RLRInvocationOperation の要求仕様は以下の通りです:

  • setValue:forKey: や valueForKey: が NSInvocationOperation のサポートするキーと共に呼ばれた場合、NSInvocationOperation の挙動を邪魔しない
  • setValue:forKey: が NSInvocationOperation のサポートしないキーと共に呼ばれた場合、そのキーに値を設定する。値が nil の場合は、キーに設定されていた値をクリアする
  • valueForKey: が NSInvocationOperation のサポートしないキーと共に呼ばれた場合、そのキーに設定されている値、なければ nil を返す

そして、以下が RLRInvocationOperation のコードです。
NSInvocationOperation がサポートしていないキーと値の容れ物として _kvcDict というインスタンス変数を使っています。

@interface RLRInvocationOperation : NSInvocationOperation
{
    NSMutableDictionary *_kvcDict;
}
@end


@implementation RLRInvocationOperation

//--------------------------------------------------------------//
#pragma mark -- Initialize --
//--------------------------------------------------------------//

- (void)_init
{
    // Create _kvcDict
    _kvcDict = [[NSMutableDictionary alloc] init];
}

- (id)initWithInvocation:(NSInvocation *)inv
{
    // Super
    self = [super initWithInvocation:inv];
    if (!self) {
        return nil;
    }
    
    // Initialize self
    [self _init];
    
    return self;
}

- (id)initWithTarget:(id)target selector:(SEL)sel object:(id)arg
{
    // Super
    self = [super initWithTarget:target selector:sel object:arg];
    if (!self) {
        return nil;
    }
    
    // Initialize self
    [self _init];
    
    return self;
}

- (void)dealloc
{
    // Clean up
    [_kvcDict release], _kvcDict = nil;
    
    // Super
    [super dealloc];
}

//--------------------------------------------------------------//
#pragma mark -- KVC Compliant Container --
//--------------------------------------------------------------//

- (id)valueForUndefinedKey:(NSString *)key
{
    // Validate key
    id validatedKey;
    if (key) {
        validatedKey = key;
    }
    else {
        validatedKey = [NSNull null];
    }
    
    // Return value for validatedKey
    return [_kvcDict objectForKey:validatedKey];
}

- (void)setValue:(id)value forUndefinedKey:(NSString *)key
{
    // Validate key
    id validatedKey;
    if (key) {
        validatedKey = key;
    }
    else {
        validatedKey = [NSNull null];
    }
    
    // Update _kvcDict
    if (value) {
        [_kvcDict setObject:value forKey:validatedKey];
    }
    else {
        [_kvcDict removeObjectForKey:validatedKey];
    }
}

@end

コード中、setValue:forKey: や valueForKey: をオーバーライドしていません。代わりに、setValue:forUndefinedKey: や valueForUndefinedKey: をオーバーライドしています。setValue:forKey: や valueForKey: が NSInvocationOperation のサポートしないキーと共に呼ばれたとき、それぞれ setValue:forUndefinedKey: , valueForUndefinedKey: に処理が渡ってくるからで、ここに独自の実装を書いておけば、NSInvocationOperation のもともとの挙動を邪魔しないで済むからです。

これで RLRInvocationOperation の完成です。RLRInvocationOperation には、任意のキーに任意の値を設定することができます。

Advertisements

From → Develop

Leave a Comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s