Skip to content

KVC: Set And Array Operators 複数使い

2010.09.20

KVC (Key-Value Coding) の Set And Array Operators をマスターすると、コードを簡素化できたり、NSPredicate でできることの幅が増えたり、Cocoa Bindings でできることの幅が増えるなどの利点があります。Set And Array Operators の概要から始まったシリーズ。

これまでの数回で、Set And Array Operators の基本的な使い方をマスターしました。今回は、Set And Array Operators のもう少し高度な使い方として、Set And Array Operators をひとつのキーパスに複数入れる技を紹介したいと思います。


Set And Array Operators は、ひとつのキーパスに複数入れることができます。この技をマスターすると、valueForKeyPath: で取得できるオブジェクトの幅が広がります。

まずはおさらいです。Set And Array Operators のフォーマットは次のようなものでした。

[obj valueForKeyPath:
    @"keyPathToSetOrArray.@operator.keyPathToProperty"];

obj が valueForKeyPath: メソッドのレシーバです。[obj valueForKeyPath:@”keyPathToSetOrArray”] で取得される NSArray や NSSet が @operator を実行するように言われるオブジェクト、オペレータのレシーバです。
オペレータのレシーバは、@operator を実行するように言われると、自分の要素それぞれに対して valueForKeyPath:@”keyPathToProperty” を呼び、それによって得られたオブジェクトを使って、その平均値を計算したり、合計値を計算したりして、その結果を返します。

ここで、オペレータのレシーバの各要素が valueForKeyPath:@”keyPathToProperty” を実行するように言われることに注目します。

[element valueForKeyPath:@"keyPathToProperty"];

ここでもまた Set And Array Operators を使うことはできないか? 例えば次のように。

[element valueForKeyPath:
    @"keyPathToArrayOrSet.@operator.keyPathToProperty"];

その答えは「できる」となります。

obj から辿ると、以下のようなことが「できる」ということになります。

[obj valueForKeyPath:
    @"keyPathToSetOrArray1.@operator1.keyPathToSetOrArray2.@operator2.keyPathToProperty"];

最後の “keyPathToProperty” を “keyPathToSetOrArray3.@operator3.keyPathToProperty” とすることもできます。さらに、この最後の “keyPathToProperty” を “keyPathToSetOrArray4.@operator4.keyPathToproperty” とすることができます‥‥と、ずっと続いて、「Set And Array Operators は、ひとつのキーパスに複数入れることができる」となります。

では実際に見ていきましょう。と言っても、実はもう既に @unionOfObjects の回でやりました。次のようなものでした。

問:以下のような NSDictionary 型変数 bowling があるとき、player A, B, C それぞれのスコア平均を格納した配列を取得せよ。

bowling = {
    players = (
        {
            name = A;
            scores = (
                120,
                150,
                180
            );
        },
        {
            name = B;
            scores = (
                170,
                190,
                120
            );
        },
        {
            name = C;
            scores = (
                50,
                250
            );
        }
    );
}

答えは次のようになりました。

NSArray *averages;
averages = [bowling valueForKeyPath:
    @"players.@unionOfObjects.scores.@avg.self"];
// averages = (150, 160, 150)

また、次のようにすることもできます。

NSArray *averages;
averages = [bowling valueForKeyPath:
    @"players.scores.@unionOfObjects.@avg.self"];

これは、[bowling valueForKeyPath:@”players.scores”] で得られるオブジェクトが、scores 配列を要素とする配列 (scoresArray) となり、scoresArray が @”unionOfObjects.@avg.self” を解決する過程で、scores が @”avg.self” を解決するという構造になります。
scoresArray:

scoresArray = (
    (
        120,
        150,
        180
    ),
    (
        170,
        190,
        120
    ),
    (
        50,
        250
    )
)

他にもいろいろ見ていきましょう。

問:最高得点を求めよ

NSNumber *maxScore;
maxScore = [bowling valueForKeyPath:
    @"players.@max.scores.@max.self"];
// maxScore = 250

問:最高の平均点を求めよ

NSNumber *maxAverage;
maxAverage = [bowling valueForKeyPath:
    @"players.@max.scores.@avg.self"];
// maxAverage = 160

問:player A, B, C の総得点を求めよ

NSNumber *sumOfScores;
sumOfScores = [bowling valueForKeyPath:
    @"players.@sum.scores.@sum.self"];
// sumOfScores = 1230

問:総ゲーム数を求めよ

NSNumber *allGameCount;
allGameCount = [bowling valueForKeyPath:
    @"players.@sum.scores.@count"];
// allGameCount = 8

ひとつのキーパスに複数のオペレータを入れる技を使って、オペレータひとつでは成し得なかったことができるようになりました。次回は、KVC に於ける NSDictionary の特別な挙動を取り上げます。

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