Skip to content

KVC に於ける NSSet と NSArray の特別な挙動

2010.09.26

KVC (Key-Value Coding) に於ける NSSet と NSArray の挙動は特殊なものとなっています。これを把握しておくと、NSPredicate でできることの幅が増えたり、Cocoa Bindings でできることの幅が増えるなどの利点があります。

今回は、KVC に於ける NSSet と NSArray の挙動を確認します。


NSSet と NSArray の valueForKey: メソッドは、NSObject のそれとは少し違う挙動を取ります。

[setOrArray valueForKey:key];

このとき、NSSet は、自分が持っている各メンバーに対して valueForKey: を実行し、それによって得られたオブジェクトをセットに収集し返します。

// Make set
NSSet *set;
set = [NSSet setWithObjects:
    [NSDictionary dictionaryWithObject:@"Hello" forKey:@"greeting"],
    [NSDictionary dictionaryWithObject:@"Bonjour" forKey:@"greeting"],
    nil];

// Execute valueForKey:
id result;
result = [set valueForKey:@"greeting"];
NSLog(@"result (%@) = %@", NSStringFromClass([result class]), result);
/*
result (NSCFSet) = {(
    Hello,
    Bonjour
)}
*/

同じように、NSArray は、自分が持っている各要素に対して valueForKey: を実行し、それによって得られたオブジェクトを配列に収集し返します。

// Make array
NSArray *array;
array = [NSArray arrayWithObjects:
    [NSDictionary dictionaryWithObject:@"Hello" forKey:@"greeting"],
    [NSDictionary dictionaryWithObject:@"Bonjour" forKey:@"greeting"],
    nil];

// Execute valueForKey:
id result;
result = [array valueForKey:@"greeting"];
NSLog(@"result (%@) = %@", NSStringFromClass([result class]), result);
/*
result (NSCFArray) = (
    Hello,
    Bonjour
)
*/

ここからはドキュメント化されていない情報です。
NSArray や NSSet に、普段通りの挙動をしてもらいたいときは、key の頭に “@” を付けます。前回の NSDictionary のときと同じ要領です。こうすることで、[super valueForKey:key] が呼ばれ、普段通りの挙動になります。

以下のコードは、先程の set から anyObject を取得しています。

id anyObject;
anyObject = [set valueForKey:@"@anyObject"];
NSLog(@"anyObject = %@", anyObject);
/*
anyObject = {
    greeting = Hello;
}
*/

以下のコードは、先程の array から lastObject を取得しています。

id lastObject;
lastObject = [array valueForKey:@"@lastObject"];
NSLog(@"lastObject = %@", lastObject);
/*
lastObject = {
    greeting = Bonjour;
}
*/

NSArray や NSSet に独自のメソッドを追加した場合も例外ではありません。

以下のコードは、NSArray に firstObject というメソッドを追加しています。

@interface NSArray (RLRExtension)
- (id)firstObject;
@end

@implementation NSArray (RLRExtension)
- (id)firstObject
{
    @synchronized(self) {
        if ([self count]) {
            return [self objectAtIndex:0];
        }
        
        return nil;
    }
}
@end

上のようにしておけば、valueForKey:@”@firstObject” で firstObject メソッドの返り値を取得することができます。

id firstObject;
firstObject = [array valueForKey:@"@firstObject"];
NSLog(@"firstObject = %@", firstObject);
/*
firstObject = {
    greeting = Hello;
}
*/
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