objectForKey
とvalueForKey
の違いは何ですか?私は両方のドキュメントを調べましたが、それらは私には同じように見えました。
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 も確認できます。
お役に立てば幸いです。
valueForKey:
を実行する場合、NSStringを指定する必要がありますが、objectForKey:
はNSObjectサブクラスをキーとして使用できます。これは、キー値コーディングの場合、キーが常に文字列であるためです。
実際、ドキュメントでは、valueForKey:
にNSStringを指定した場合でも、objectForKey:
で始まる文字列でない限り、@
を呼び出します。その場合、[super valueForKey:]
を呼び出し、valueForUndefinedKey:
を呼び出します。
これは、objectForKey:
の代わりに可能な限りvalueForKey:
を使用する大きな理由です-未知のキーを持つvalueForKey:
は、「このクラスはキーのキー値コーディングに準拠していません」と言ってNSUnknownKeyException
をスローします。
前述のように、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
の値は、同じ種類のオブジェクトによってアクセスされます。
ここで包括的な答えを提供しようとします。ポイントの多くは他の回答に表示されますが、各回答が不完全で、一部が間違っていることがわかりました。
何よりもまず、objectForKey:
はNSDictionary
メソッドであり、valueForKey:
は、KSD苦情クラス(NSDictionaryを含む)に必要なKVCプロトコルメソッドです。
さらに、@ dreamlaxが書いたように、ドキュメントは、NSDictionary
がvalueForKey:
メソッドを実装することを示唆していますUSING its objectForKey:
実装。つまり、[NSDictionary valueForKey:]
は[NSDictionary objectForKey:]
を呼び出します。
これは、valueForKey:
が(同じ入力キーで)objectForKey:
より速くなることはないことを意味しますが、私が行った徹底的なテストでは、約5%から15%の違い、 NSDictionary。通常の状況では、違いはごくわずかです。
次:KVCプロトコルはNSString *
キーでのみ機能するため、valueForKey:
はキーとしてNSString *
(またはサブクラス)のみを受け入れますが、NSDictionary
は他の種類のオブジェクトで機能しますキー-「下位レベル」objectForKey:
がキーとしてコピー可能な(NSCopyingプロトコルに準拠した)オブジェクトを受け入れるようにします。
最後に、NSDictionary's
のvalueForKey:
実装は、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);
}