简体   繁体   中英

What's the difference between Key-Value Coding and NSDictionary?

What's the difference between Key-Value Coding and NSDictionary? KVC has addValue:forKey and NSDicationary has addObject:forKey, which gives me the impression that they're very similar structures.

What is Key-Value Coding? :

Key-value coding is a mechanism for accessing an object's properties indirectly, using strings to identify properties, rather than through invocation of an accessor method or accessing them directly through instance variables. In essence, key-value coding defines the patterns and method signatures that your application's accessor methods implement.

NSDictionary Class Reference :

The NSDictionary class declares the programmatic interface to objects that manage immutable associations of keys and values.

So,

  • NSDictionary is an object, while key-value coding is a protocol
  • NSDictionary can store and retrieve objects, while key-value coding must rely on some other form of storage

Key-Value Coding is commonly used with Key-Value Observation (see below), although there are other uses. For example:

  • KVC allows you to string together properties in a string, even without importing those classes. (For example, to see my landlord's other tenants, you might retrieve aaronBrager.apartment.landlord.tenants ).
  • KVC allows the use of collection operators like @avg , @sum , and @count .

If you're not sure what you should use, I suggest learning to use NSDictionary and basic model objects before you venture into KVC.

See also this Stack Overflow answer which reviews some of the syntax differences.


Key-Value Observation

Commonly used with Key-Value Coding, Key-Value Observation allows your classes to be notified when the value of a particular key changes. (This is indirectly related to your question.)

There are two areas where this gets really powerful:

  1. You can use KVO to observe changes in collection objects
  2. With KVO, you can dynamically generate keys based on other keys :

     - (NSString *)fullName { return [NSString stringWithFormat:@"%@ %@",firstName, lastName]; } + (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key { NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key]; if ([key isEqualToString:@"fullName"]) { NSArray *affectingKeys = @[@"lastName", @"firstName"]; keyPaths = [keyPaths setByAddingObjectsFromArray:affectingKeys]; } return keyPaths; }

    Now anyone observing fullName will be notified when either lastName or firstName changes.

Key Value Coding is a set of conventions for accessing the contents of an object using string identifiers. KVC compliant classes have properties that follow the KVC naming convention. A number of different technologies are layered on top of KVC and depend on it to function. KVC is implemented as an informal protocol on NSObject . KVC can can be used with all descendants of NSObject, as long as the object's properties are compliant with the KVC naming conventions.

NSDictionary , in contrast, is a Foundation collection class representing a class cluster.

KVC is a fundamental concept in Cocoa, the more you know about it the better your applications will be.

I'll try to answer the exact question. the DIFFERENCE is, an NSDictionary holds arbitrary key-value pairs (eg @{ @"Oy":@"Vey", @"name":@"Motti" } but a normal NSObject descendant say:

@interface MyClass : NSObject {
  NSString *firstName;
  NSString *lastName;
}
@end
@implementation
- (id) init {
  firstName = "Bobo";
  lastName = "Link";
}
@end
 MyClass *myObj = [[MyClass alloc] init];

cannot usually be accessed via

 [myObj valueForKey:@"firstName"];

It is NOT a collection, and NOT key-value-coding compliant!

Complying with KVC (per specific property) allows you to use an ObjC object AS IF it was an NSDictionary. So if I changed the declaration of the object like thus:

@interface MyClass : NSObject {
  NSString *lastName;
}
  @property (readwrite, strong, name=firstName) NSString *firstName;
@end

to make it KVC compliant only on firsName - then calling

 [myObj valueForKey:@"firstName"];

would yield the expected value @"Bobo" .

That's about the difference. However, KVC goes well beyond allowing simple dictionary-like access to objects with key-value semantics.

It introduces the concept of keyPath , where you can "drill" through succession of objects and properties like in [myBankAccount valueForKeyPath:@"addresses.billingAddress.city"] , or to evaluate and extract collections of values "drilled" at keyPaths (eg [personObject valueForKeyPath:@"friends.firstName"] will collect an NSArray of firstNames of all your friends, provided that friends is a collection (say NSArray ) of Friend objects each having a KVC compliant property named firstName .

But it doesn't stop even there -- KVC provides special key-path elements (like @avg , @sum , SELF , @distinctUnionOfObjects and others) that when correctly used inside key paths allow for smart evaluation of accumulations and summaries of collected values, saving tons of loops and lines of codes. They also look fancy and are very readable. For example: [accounts valueForKeyPath:@"transactions.@avg.amount"] will scan all the accounts. For each account it will again scan its transactions , collecting their amount . It will then average the amounts of all transactions of an account, and will finally collect and return an NSArray of NSNumber s, containing average-amounts per account. That's concise and powerful coding.

Other answers already provide lots of good links for documentation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM