ObjectForKey ve valueForKey arasındaki fark?


Yanıtlar:


403

objectForKey:bir NSDictionaryyöntemdir. An NSDictionary, birine benzer bir koleksiyon sınıfıdır NSArray, dizinler kullanmak yerine öğeler arasında ayrım yapmak için anahtarlar kullanır. Anahtar, verdiğiniz rastgele bir dizedir. Hiçbir iki nesne aynı anahtara sahip olamaz (tıpkı bir içindeki iki nesne NSArrayaynı dizine sahip olamaz gibi).

valueForKey:bir KVC yöntemidir. HERHANGİ bir sınıfla çalışır. valueForKey:bir özelliğin adı için bir dize kullanarak erişmenize olanak tanır. Örneğin, Accountbir özelliği olan bir sınıf varsa accountNumber, aşağıdakileri yapabilirim:

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

[newAccount setAccountNumber:anAccountNUmber];

NSNumber *anotherAccountNumber = [newAccount accountNumber];

KVC kullanarak, özelliği dinamik olarak erişebilirsiniz:

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

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

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

Bunlar eşdeğer ifade kümeleridir.

Düşündüğünü biliyorum: vay, ama alaycı bir şekilde. KVC o kadar kullanışlı görünmüyor. Aslında, "wordy" görünüyor. Ancak çalışma zamanında bir şeyleri değiştirmek istediğinizde, diğer dillerde çok daha zor olan birçok harika şey yapabilirsiniz (ancak bu, sorunuzun kapsamının dışındadır).

KVC hakkında daha fazla bilgi edinmek istiyorsanız, özellikle Scott Stevenson'ın blogunda Google kullanıyorsanız birçok öğretici var . NSKeyValueCoding Protokol Başvurusu'na da göz atabilirsiniz .

Umarım yardımcı olur.


12
valueForKey, anahtarın @ simgesiyle başlayıp başlamamasına bağlı olarak NSDictionary nesneleri için farklı davranır.
dreamlax

61
objectForKey: herhangi bir nesneyi yalnızca dizeler olarak değil, anahtar olarak kabul eder. Tek gereklilik, anahtarın NSCopying protokolünü desteklemesidir.
Ashley Clark

5
Kimse bu cevabı valueForKey'e işaret ederek düzeltmediğine şaşırdım: teknik olarak size karşılık gelen örnek değişkenine erişim vermez, daha çok örnek değişkenini yönetebilen erişimci yöntemi.
Dany Joumaa

7
Uyarı: valueForKey son derece yavaş olabilir - şu anda iPad uygulamamda büyük bir darboğaz var, o kadar yavaş ki "standart" bir sözlükle değiştirmek uygulamayı belirgin şekilde daha hızlı hale getirdi. İOS'ta KVC ile ilgili çok yanlış bir şey ve bunu bir daha asla kullanmayacağım - performanstaki düşüşe değmez ve yine de uzun yolla yeniden yazmak zorunda kalmazsınız. Bu, CALayers'ta NSString değerlerine sahip NSString anahtarlarını kullanıyordu. Enstrümanlar "CAObject_valueForKey" toplam çalışma süresinin% 25'i olduğunu gösterdi (!)
Adam

2
@Adam Bu korkutucu geliyor. İOS7'den beri tekrar denediniz mi? Eğer öyleyse, o zamandan beri işler değişti mi?
Unheilig

64

Ne zaman valueForKey:bunu bir NSString vermek gerekir, oysa objectForKey:herhangi bir NSObject alt sınıfı bir anahtar olarak alabilir. Bunun nedeni, Anahtar-Değer Kodlaması için, anahtarların her zaman dize olmasıdır.

Aslında, belgeler valueForKey:bir NSString verdiğinizde bile objectForKey:, dize bir ile başlamadığı sürece yine de çağıracağını @belirtir, bu durumda çağırır [super valueForKey:]ve bu durum valueForUndefinedKey:bir istisna oluşturabilir.


Lütfen bana demek istediğin belgelerin bağlantısını verebilir misin? teşekkür ederim.
Ali Amin

5
@ عليامين: Tam burada
dreamlax

20

objectForKey:Mümkün olan her yerde kullanmak için harika bir neden valueForKey:- valueForKey:bilinmeyen bir anahtarla NSUnknownKeyException"bu sınıf anahtar için kodlama ile uyumlu anahtar değer değil" diyecektir.


5
"valueForKey: bilinmeyen bir anahtar ile NSUnknownKeyException" bu sınıf anahtar için kodlama ile uyumlu anahtar değer değildir "
diyecektir iyi

NSDictionary için bu doğru değildir ve bunu deneyebilirsiniz: NSLog (@ "Z:% @", [@ {@ "X": @ (10), @ "Y": @ (20)} valueForKey: @, "Z"]); valueForKey, belirtilen bir anahtarı desteklemeyen diğer sınıflarda bu tür istisnalar yayar - ancak NSDictionary alt sınıfları için - sadece sessiz bir sıfır alırsınız.
Şunu

13

objectForKey:Söylendiği gibi, veri tipi :(id)aKeyise valueForKey:veri tipidir :(NSString *)key.

Örneğin:

 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. 

Yani, valueForKey:sadece bir dize değeri alır ve bir KVC yöntemidir, oysa objectForKey:herhangi bir nesne türünü alır.

İçindeki değere objectForKeyaynı türden bir nesne tarafından erişilir.


0

Burada kapsamlı bir cevap vermeye çalışacağım. Noktaların çoğu diğer cevaplarda ortaya çıkıyor, ancak her cevabı eksik buldum ve bazılarını yanlış buldum.

Birincisi ve en önemlisi, objectForKey:bir olduğunu NSDictionaryiken, yöntem valueForKey:NSDictionary dahil - hiçbir KVC şikayet sınıfının gerektirdiği bir KVC protokol yöntemidir.

@Dreamlax, dokümantasyon ipuçları yazdığı gibi Dahası, bu NSDictionaryonun uygulayan valueForKey:yöntemi KULLANMA onun objectForKey:uygulanmasını. Başka bir deyişle - [NSDictionary valueForKey:]çağrılar [NSDictionary objectForKey:].

Bu valueForKey:, hiçbir zaman objectForKey:(aynı giriş anahtarında) daha hızlı olamaz , ancak kapsamlı testler yaptığım büyük bir NSDictionary milyarlarca rastgele erişim üzerinden yaklaşık% 5 ila% 15 fark anlamına gelir. Normal durumlarda - fark ihmal edilebilir.

Sonraki: KVC protokolü yalnızca NSString *anahtarlarla çalışır , bu nedenle anahtar olarak valueForKey:yalnızca bir NSString *(veya alt sınıf) kabul ederken NSDictionary, diğer nesne türleriyle anahtar olarak çalışabilir - böylece "alt seviye" objectForKey:herhangi bir kopyalanabilir (NSCopying protokolü uyumlu) nesneyi kabul eder anahtar olarak.

Son olarak, NSDictionary'suygulama valueForKey:KVC'nin belgelerinde tanımlanan standart davranıştan sapar ve NSUnknownKeyExceptionbulamadığı bir anahtar için DEĞİLDİR - bu "özel" bir anahtar değilse - '@' ile başlayan - genellikle " toplama "işlev tuşu (örn. @"@sum, @"@avg"). Bunun yerine, NSDictionary'de bir anahtar bulunamadığında bir sıfır döndürür - aynı şekilde davranırobjectForKey:

Notlarımı göstermek ve kanıtlamak için bazı test kodları aşağıdadır.

- (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);
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.