web-dev-qa-db-ja.com

objectForKeyとvalueForKeyの違いは?

objectForKeyvalueForKeyの違いは何ですか?私は両方のドキュメントを調べましたが、それらは私には同じように見えました。

341
Devoted

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

valueForKey:はKVCメソッドです。どのクラスでも機能します。 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について詳しく知りたい場合は、特に Scott Stevensonのブログ でGoogleを使用している場合、多くのチュートリアルがあります。 NSKeyValueCoding Protocol Reference も確認できます。

お役に立てば幸いです。

400
Corey Floyd

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

実際、ドキュメントでは、valueForKey:にNSStringを指定した場合でも、objectForKey:で始まる文字列でない限り、@を呼び出します。その場合、[super valueForKey:]を呼び出し、valueForUndefinedKey:を呼び出します。

63
dreamlax

これは、objectForKey:の代わりに可能な限りvalueForKey:を使用する大きな理由です-未知のキーを持つvalueForKey:は、「このクラスはキーのキー値コーディングに準拠していません」と言ってNSUnknownKeyExceptionをスローします。

21
Nick Locking

前述のように、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の値は、同じ種類のオブジェクトによってアクセスされます。

12
Harjot Singh

ここで包括的な答えを提供しようとします。ポイントの多くは他の回答に表示されますが、各回答が不完全で、一部が間違っていることがわかりました。

何よりもまず、objectForKey:NSDictionaryメソッドであり、valueForKey:は、KSD苦情クラス(NSDictionaryを含む)に必要なKVCプロトコルメソッドです。

さらに、@ dreamlaxが書いたように、ドキュメントは、NSDictionaryvalueForKey:メソッドを実装することを示唆していますUSING its objectForKey:実装。つまり、[NSDictionary valueForKey:][NSDictionary objectForKey:]を呼び出します。

これは、valueForKey:が(同じ入力キーで)objectForKey:より速くなることはないことを意味しますが、私が行った徹底的なテストでは、約5%から15%の違い、 NSDictionary。通常の状況では、違いはごくわずかです。

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

最後に、NSDictionary'svalueForKey:実装は、KVCのドキュメントで定義されている標準の動作から逸脱し、見つからないキーに対してNSUnknownKeyExceptionを発行しません-これが「特殊」でない限りkey-「@」で始まるもの-通常は「集約」ファンクションキーを意味します(例:@"@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);
}
0
Motti Shneor