objectForKeyとvalueForKeyの違いは?


回答:


403

objectForKey:あるNSDictionary方法。AnはNSDictionaryに似たコレクションクラスでNSArray、代わりにインデックスを使用する場合を除き、それはアイテムを区別するためにキーを使用しています。キーは、ユーザーが指定する任意の文字列です。2つのオブジェクトが同じキーを持つことはできません(同じオブジェクトに2つのオブジェクトがNSArray同じインデックスを持つことはできません)。

valueForKey:KVCメソッドです。ANYクラスで動作します。valueForKey:名前に文字列を使用してプロパティにアクセスできます。たとえば、Accountプロパティを持つクラスがある場合accountNumber、次のようにできます。

NSNumber *anAccountNumber = [NSNumber numberWithInt:12345];
Account *newAccount = [[Account alloc] init];

[newAccount setAccountNumber:anAccountNUmber];

NSNumber *anotherAccountNumber = [newAccount accountNumber];

KVCを使用して、プロパティに動的にアクセスできます。

NSNumber *anAccountNumber = [NSNumber numberWithInt:12345];
Account *newAccount = [[Account alloc] init];

[newAccount setValue:anAccountNumber forKey:@"accountNumber"];

NSNumber *anotherAccountNumber = [newAccount valueForKey:@"accountNumber"];

それらは同等のステートメントのセットです。

私はあなたが考えていることを知っています:うわー、しかし皮肉なことに。KVCはそれほど便利に見えません。実際、それは「言葉っぽい」ように見えます。しかし、実行時に物事を変更したい場合、他の言語でははるかに難しい多くのクールなことができます(ただし、これは質問の範囲を超えています)。

KVCについてさらに詳しく知りたい場合は、特にスコットスティーブンソンのブログでGoogleのチュートリアルをご覧ください。NSKeyValueCodingプロトコルリファレンスご覧ください。

お役に立てば幸いです。


12
キーが@記号で始まるかどうかに応じて、NSDictionaryオブジェクトのvalueForKeyの動作は異なります。
dreamlax 2009年

61
objectForKey:文字列だけでなく、任意のオブジェクトをキーとして受け入れます。唯一の要件は、キーがNSCopyingプロトコルをサポートすることです。
アシュリークラーク

5
valueForKeyを指摘して誰もこの答えを修正していないことに驚いています。技術的には対応するインスタンス変数へのアクセスではなく、インスタンス変数を管理する(できる)アクセサーメソッドを提供します。
Dany Joumaa 2012年

7
警告:valueForKeyは非常に遅くなる可能性があります-現在のところ、これは私のiPadアプリの主要なボトルネックです。そのため、「標準」辞書に置き換えるとアプリが著しく速くなります。iOSのKVCに何か問題があり、私は二度とそれを使用しません-パフォーマンスの低下の価値がなく、とにかく長い道のりで書き直す必要があります。これは、CALayersでNSString値を持つNSStringキーを使用していました。Instrumentsは、「CAObject_valueForKey」が合計実行時間の25%(!)であることを示しました
Adam

2
@アダムそれは怖いですね。iOS7からもう一度試しましたか?もしそうなら、物事はその後変化しましたか?
Unheilig 2014年

64

その場合はvalueForKey:、NSStringを指定する必要がありますが、objectForKey:任意のNSObjectサブクラスをキーとして使用できます。これは、Key-Valueコーディングの場合、キーが常に文字列であるためです。

実際には、あなたが与えるも、ドキュメントの状態valueForKey:NSStringのは、それが起動しますobjectForKey:と、文字列が開始されない限り、いずれにせよ@、それが呼び出されます。その場合には、[super valueForKey:]呼び出すことができ、valueForUndefinedKey:例外を発生させる可能性があります。


意味のあるドキュメントのリンクを教えてください。ありがとうございました。
Ali Amin

5
@عليامين:それがここにある
dreamlax

20

ここで使用するのに最適な理由ですobjectForKey:可能な限りの代わりにvalueForKey:-をvalueForKey:未知のキーでは、スローされますNSUnknownKeyException、「このクラスは、キーのための準拠のコーディングキー値ではありません」と述べました。


5
「valueForKey:不明なキーを持つNSUnknownKeyExceptionがスローされ、「このクラスはキーのコーディングに準拠したキー値ではありません」
onmyway133

これは単にNSDictionaryには当てはまりません。NSLog(@ "Z:%@"、[@ {@ "X":@(10)、@ "Y":@(20)}を試してみてください。 valueForKey:@ "Z"]); valueForKeyは、指定されたキーをサポートしない他のクラスでこのような例外を発行しますが、NSDictionaryサブクラスでは、静かなnilを受け取ります。これを試してください:
Motti Shneor

13

前記のように、objectForKey:データ型である:(id)aKeyのに対し、valueForKey:データ型であります:(NSString *)keyです。

例えば:

 NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:[NSArray arrayWithObject:@"123"],[NSNumber numberWithInteger:5], nil];

 NSLog(@"objectForKey : --- %@",[dict objectForKey:[NSNumber numberWithInteger:5]]);  
    //This will work fine and prints (    123    )  

 NSLog(@"valueForKey  : --- %@",[dict valueForKey:[NSNumber numberWithInteger:5]]); 
    //it gives warning "Incompatible pointer types sending 'NSNumber *' to parameter of type 'NSString *'"   ---- This will crash on runtime. 

したがって、valueForKey:文字列値のみを受け取り、KVCメソッドですが、objectForKey:任意のタイプのオブジェクトを受け取ります。

の値にobjectForKeyは、同じ種類のオブジェクトがアクセスします。


0

ここで包括的な答えを提供するように努めます。ポイントの多くは他の回答にも出ていますが、私はそれぞれの回答が不完全で、一部が間違っていることに気付きました。

何よりobjectForKey:もまず、NSDictionaryメソッドですが、valueForKey: NSDictionaryのを含む-任意KVCのクレームクラスに要求KVCプロトコル方式です。

さらに、@dreamlaxように、その、ドキュメントのヒントを書いたNSDictionaryその実装valueForKey:方法を使用したそのobjectForKey:実装を。言い換えれば[NSDictionary valueForKey:][NSDictionary objectForKey:]

これは、それが、意味valueForKey:よりも速くなることはありませんobjectForKey:(同じ入力キーで)ます。通常の状況では、違いはごくわずかです。

次へ:KVCプロトコルはNSString *キーでのみ機能するため、キー(またはサブクラス)valueForKey:のみをNSString *キーとして受け入れ、NSDictionary他の種類のオブジェクトはキーとして機能します-「下位レベル」objectForKey:はコピー可能な(NSCopyingプロトコルに準拠した)オブジェクトを受け入れますキーとして。

最後に、のNSDictionary's実装はvalueForKey:、KVCのドキュメントで定義されている標準の動作から逸脱し、NSUnknownKeyException「特殊な」キー(「@」で始まるキーでない限り、通常は「集約」ファンクションキー(例@"@sum, @"@avg")。代わりに、NSDictionaryでキーが見つからない場合は単にnilを返します。objectForKey:

以下は、私のメモを実証および証明するためのテストコードです。

- (void) dictionaryAccess {
    NSLog(@"Value for Z:%@", [@{@"X":@(10), @"Y":@(20)} valueForKey:@"Z"]); // prints "Value for Z:(null)"

    uint32_t testItemsCount = 1000000;
    // create huge dictionary of numbers
    NSMutableDictionary *d = [NSMutableDictionary dictionaryWithCapacity:testItemsCount];
    for (long i=0; i<testItemsCount; ++i) {
        // make new random key value pair:
        NSString *key = [NSString stringWithFormat:@"K_%u",arc4random_uniform(testItemsCount)];
        NSNumber *value = @(arc4random_uniform(testItemsCount));
        [d setObject:value forKey:key];
    }
    // create huge set of random keys for testing.
    NSMutableArray *keys = [NSMutableArray arrayWithCapacity:testItemsCount];
    for (long i=0; i<testItemsCount; ++i) {
        NSString *key = [NSString stringWithFormat:@"K_%u",arc4random_uniform(testItemsCount)];
        [keys addObject:key];
    }

    NSDictionary *dict = [d copy];
    NSTimeInterval vtotal = 0.0, ototal = 0.0;

    NSDate *start;
    NSTimeInterval elapsed;

    for (int i = 0; i<10; i++) {

        start = [NSDate date];
        for (NSString *key in keys) {
            id value = [dict valueForKey:key];
        }
        elapsed = [[NSDate date] timeIntervalSinceDate:start];
        vtotal+=elapsed;
        NSLog (@"reading %lu values off dictionary via valueForKey took: %10.4f seconds", keys.count, elapsed);

        start = [NSDate date];
        for (NSString *key in keys) {
            id obj = [dict objectForKey:key];
        }
        elapsed = [[NSDate date] timeIntervalSinceDate:start];
        ototal+=elapsed;
        NSLog (@"reading %lu objects off dictionary via objectForKey took: %10.4f seconds", keys.count, elapsed);
    }

    NSString *slower = (vtotal > ototal) ? @"valueForKey" : @"objectForKey";
    NSString *faster = (vtotal > ototal) ? @"objectForKey" : @"valueForKey";
    NSLog (@"%@ takes %3.1f percent longer then %@", slower, 100.0 * ABS(vtotal-ototal) / MAX(ototal,vtotal), faster);
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.