iOS学习笔记03—Key-Value-Coding(KVC,键/值编码)

来源:互联网 发布:php网页免费游戏源码 编辑:程序博客网 时间:2024/05/21 06:20

iOS学习笔记03—Key-Value-Coding(KVC,键/值编码)


1、为什么苹果提供了KVC机制?什么是KVC

答:简化代码,编程方便呀。

KVC的基本调用包括-valueForKey:-setValue:forKey:。以字符串的形式向对象发送消息,这个字符串是我们关注的属性的关键信息。

看下面两段代码NSTableView委托方法的对比

1)不使用KVC的代码:

- (id)tableView:(NSTableView *)tableview

objectValueForTableColumn:(id)column row:(NSInteger)row {

    ChildObject *child = [childrenArray objectAtIndex:row];

   if ([[column identifier] isEqualToString:@"name"]) {

       return [child name];

    }

   if ([[column identifier] isEqualToString:@"age"]) {

       return [child age];

    }

   if ([[column identifier] isEqualToString:@"favoriteColor"]) {   

       return [child favoriteColor];

    }

   // And so on. 

}


2)使用KVC的代码:

- (id)tableView:(NSTableView *)tableview

objectValueForTableColumn:(id)column row:(NSInteger)row {

    ChildObject *child = [childrenArray objectAtIndex:row];

   return [child valueForKey:[column identifier]];

}


2KVC的缺点

KVC这么有用,为什么没有用它来处理所有对象,并抛弃存取方法?KVC有什么缺点呢?

答:因为KVC需要解析字符串来计算你需要的答案,因此速度比较慢。另外编译器无法对它进行错误检查。


3、对于KVCCocoa自动放入和取出标量值。

也就是说,当使用-setValue:forKey:时,它自动将标量值(intfloatstruct)放入NSNumberNSValue中;当使用-valueForKey:时,它自动将这些标量值从这些对象中取出。仅KVC具有这种自动包装功能,常规方法调用和属性语法不具备该功能。

如果在调用-setValue:forKey:之中设置一个标量值,需要将他包装起来。

比如

[car setValue: [NSNumber numberWithFloat: 25062.4] forKey: @”mileage”];

属性mileage是标量(float类型),所以要用NSNumber包装起来。


[car setValue: @”Harold” forKey: @”name”];

上面的代码功能是,它首先查找属性namesetter方法-setName,并使用参数@”Harold”调用它。如果不存在setter方法,它将在类中产找名为name_name的实例变量,然后为它赋值。


题外话:编译器和苹果公司都以下划线开头的形式保存实例变量名称,如果你尝试在其他地方使用下划线,可能出现严重的错误。这条规则不是强制性的,但是如果不遵守它,你可能会遇到某种风险。


4KVC还支持指定关键路径,可以遵循一系列关系来指定该路径。

比如

[car setValue: [NSNumber numberWithInt: 155] 

  forKeyPath: @”engine.horsepower”];

这些路径的深度是任意的,具体取决与对象图的复杂度。


5KVC的整体操作,示例如下:

NSArray *pressures = [car valueForKeyPath: @”tires.pressure”];


6KVC的集合操作:

NSNumber *count = [garage valueForKeyPath: @”cars.@count”];

cars用于获取cars属性,它是来自garageNSArray类型的值。

@count@意味着后面将进行一些运算,@count的意思是告诉KVC机制对键值路径左侧部分的结果进行计数操作。

还包括如下操作

Simple Collection Operators

@avg

@count

@max

@min

@sum


Object Operators

@distinctUnionOfObjects

@unionOfObjects


Array and Set Operators

@distinctUnionOfArrays

@unionOfArrays

@distinctUnionOfSets


7、完整示例

OK,讲了一大通,上面还是来个实际的例子吧,实际上就是Learn Objective-C on the Mac16章的例子。

源码文件清单:Car.h, Car.m, Engine.h, Engine.m, Garage.h, Garage.m, Slant6.h, Slant6.m, Tire.h, Tire.m, main.m

1Car.h

#import<Cocoa/Cocoa.h>


@classTire;

@classEngine;


@interface Car :NSObject <NSCopying> {

NSString *name;

   NSMutableArray *tires;

   Engine *engine;

NSString *make;

NSString *model;

int modelYear;

int numberOfDoors;

float mileage;

}


@property (readwrite,copy)NSString *name;

@property (readwrite,retain)Engine *engine;

@property (readwrite,copy)NSString *make;

@property (readwrite,copy)NSString *model;

@property (readwrite)int modelYear;

@property (readwrite)int numberOfDoors;

@property (readwrite)float mileage;


- (void) setTire: (Tire *) tire

         atIndex: (int) index;

- (Tire *) tireAtIndex: (int) index;

- (void) print;

@end// Car


2Car.m

#import "Car.h"

#import"Engine.h"


@implementation Car

@synthesize name;

@synthesize engine;

@synthesize make;

@synthesize model;

@synthesize modelYear;

@synthesize numberOfDoors;

@synthesize mileage;


- (id) init

{

   if (self = [superinit]) {

self.name = @"Car";

       tires = [[NSMutableArrayalloc]init];

       int i;

       for (i =0; i <4; i++) {

            [tiresaddObject: [NSNullnull]];

        }

    }

   return (self);

} // init


- (id) copyWithZone: (NSZone *) zone

{

Car *carCopy;

carCopy = [[[selfclass

allocWithZone: zone]

 init];

carCopy.name = name;

carCopy.make = make;

carCopy.model = model;

carCopy.numberOfDoors =numberOfDoors;

carCopy.mileage =mileage;

Engine *engineCopy;

engineCopy = [[enginecopy]autorelease];

carCopy.engine = engineCopy;

int i;

for (i = 0; i <4; i++) {

Tire *tireCopy;

tireCopy = [[selftireAtIndex: i]copy];

[tireCopyautorelease];

[carCopysetTire: tireCopy

atIndex: i];

}

return (carCopy);

} // copyWithZone


- (void) dealloc

{

self.name = nil;

    [tiresrelease];

    [enginerelease];

    [superdealloc];


} // dealloc


- (void) setTire: (Tire *) tire

         atIndex: (int) index

{

    [tiresreplaceObjectAtIndex: index

          withObject: tire];


} // setTire:atIndex:


- (Tire *) tireAtIndex: (int) index

{

   Tire *tire;

    tire = [tiresobjectAtIndex: index];

   return (tire);


} // tireAtIndex:


- (void) print

{

NSString *desc = [selfdescription];

NSLog (@"%@", desc);

} // print


- (NSString *) description {

NSString *desc;

desc = [NSStringstringWithFormat

@"%@, a %d %@ %@, has %d doors, %.1f miles, %d hp and %d tires",

name,modelYear,make,model,numberOfDoors,mileage, [enginehorsepower],

[tirescount]];

return desc;

} // description


- (void) setNilValueForKey: (NSString *) key {

if ([keyisEqualToString:@"mileage"]) {

mileage =0;

}else {

[supersetNilValueForKey: key];

}

} // setNilValueForKey

@end// Car


3Engine.h

#import<Cocoa/Cocoa.h>

@interface Engine :NSObject <NSCopying> {

int horsepower;

}

@property (readwrite)int horsepower;

@end// Engine



4Engine.m

#import"Engine.h"


@implementation Engine

@synthesize horsepower;

- (id) init {

if (self = [superinit]) {

horsepower =145;

}

return (self);

} // init


- (id) copyWithZone: (NSZone *) zone

{

Engine *engineCopy;

engineCopy = [[[selfclass]

 allocWithZone: zone]

 init];

[engineCopysetValue: [NSNumbernumberWithInt:horsepower]

       forKey:@"horsepower"];

return (engineCopy);

} // copyWithZone


- (NSString *) description

{

NSString *description;

description = [NSStringstringWithFormat:

 @"I am an engine.  Vrooom!  %d HP",horsepower];

return (description);

} // description

@end// Engine


5Garage.h

//

//  Garage.h

//  15.01 Car-Value-Coding

//

//  Created by markd on 8/16/08.

//  Copyright 2008 Length-O-Words.com. All rights reserved.

//

#import<Cocoa/Cocoa.h>


@classCar;


@interface Garage :NSObject {

NSString *name;

NSMutableArray *cars;

NSMutableDictionary *stuff;

}


@property (readwrite,copy)NSString *name;


- (void) addCar: (Car *) car;

- (void) print;

@end// Garage


6Garage.m

//

//  Garage.m

//  15.01 Car-Value-Coding

//

//  Created by markd on 8/16/08.

//  Copyright 2008 Length-O-Words.com. All rights reserved.

//


#import"Garage.h"

@implementation Garage

@synthesize name;


- (void) addCar: (Car *) car {

if (cars ==nil) {

cars = [[NSMutableArrayalloc]init];

}

[carsaddObject: car];

} // addCar


- (void) dealloc {

[namerelease];

[carsrelease];

[stuffrelease];

[superdealloc];

} // dealloc


- (void) print {

NSLog (@"%@:",name);

for (Car *carincars) {

NSLog (@"    %@", car);

}

} // print


- (void) setValue: (id) value  forUndefinedKey: (NSString *) key {

if (stuff ==nil) {

stuff = [[NSMutableDictionaryalloc]init];

}

[stuffsetValue: valueforKey: key];

} // setValueForUndefinedKey


- (id) valueForUndefinedKey:(NSString *)key {

id value = [stuffvalueForKey: key];

return (value);

} // valueForUndefinedKey

@end // Car


7Slant6.h

#import"Engine.h"


@interface Slant6 :Engine

@end// Slant6


8Slant6.m

#import"Slant6.h"


@implementation Slant6


- (NSString *) description

{

   return (@"I am a slant-6. VROOOM!");

} // description


@end// Slant6


9Tire.h

#import<Cocoa/Cocoa.h>


@interface Tire :NSObject <NSCopying> {  

   float pressure;

   float treadDepth;

}

@propertyfloat pressure;

@propertyfloat treadDepth;


- (id) initWithPressure: (float) pressure;

- (id) initWithTreadDepth: (float) treadDepth;

- (id) initWithPressure: (float) pressure

       treadDepth: (float) treadDepth;


@end// Tire


10Tire.m

#import "Tire.h"


@implementation Tire

@synthesize pressure;

@synthesize treadDepth;


- (id) init

{

   if (self = [selfinitWithPressure:34

                    treadDepth:20]) {

    }

   return (self);

} // init



- (id) copyWithZone: (NSZone *) zone

{

Tire *tireCopy;

tireCopy = [[[selfclass]allocWithZone: zone]

initWithPressure:pressure

treadDepth:treadDepth];

return (tireCopy);

} // copyWithZone


- (id) initWithPressure: (float) p

{

   if (self = [selfinitWithPressure: p

                    treadDepth:20.0]) {

    }

   return (self);

} // initWithPressure


- (id) initWithTreadDepth: (float) td

{

   if (self = [selfinitWithPressure:34.0

                    treadDepth: td]) {

    }

   return (self);

} // initWithTreadDepth


- (id) initWithPressure: (float) p

             treadDepth: (float) td

{

   if (self = [superinit]) {

       pressure = p;

       treadDepth = td;

    }

   return (self);

} // initWithPressure:treadDepth:


- (NSString *) description

{

   NSString *desc;

    desc = [NSStringstringWithFormat:

                        @"Tire: Pressure: %.1f TreadDepth: %.1f",

                    pressure,treadDepth];

   return (desc);

} // description


@end// Tire


11main.m

#import<Foundation/Foundation.h>

#import "Car.h"

#import"Engine.h"

#import"Garage.h"

#import"Slant6.h"

#import "Tire.h"


Car *makeCar (NSString *name, NSString *make,NSString *model,

 int modelYear,int numberOfDoors,float mileage,

 int horsepower) {

Car *car = [[[Caralloc]init]autorelease];

car.name = name;

car.make = make;

car.model = model;

car.modelYear = modelYear;

car.numberOfDoors = numberOfDoors;

car.mileage = mileage;

Slant6 *engine = [[[Slant6alloc]init]autorelease];

[enginesetValue: [NSNumbernumberWithInt: horsepower]

   forKey:@"horsepower"];

car.engine = engine;

// Make some tires.

// int i;

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

Tire * tire= [[[Tirealloc]init]autorelease];

[carsetTire: tire atIndex: i];

}

return (car);

} // makeCar


int main (int argc, constchar * argv[])

{

NSAutoreleasePool *pool;

pool = [[NSAutoreleasePoolalloc]init];

Garage *garage = [[Garagealloc]init];

garage.name =@"Joe's Garage";

Car *car;

car =makeCar (@"Herbie",@"Honda",@"CRX",1984,2,110000,58);

[garageaddCar: car];

car =makeCar (@"Badger",@"Acura",@"Integra",1987,5,217036.7,130);

[garageaddCar: car];

car =makeCar (@"Elvis",@"Acura",@"Legend",1989,4,28123.4,151);

[garageaddCar: car];

car =makeCar (@"Phoenix",@"Pontiac",@"Firebird",1969,2,85128.3,345);

[garageaddCar: car];

car =makeCar (@"Streaker",@"Pontiac",@"Silver Streak",1950,2,39100.0,36);

[garageaddCar: car];

car =makeCar (@"Judge",@"Pontiac",@"GTO",1969,2,45132.2,370);

[garageaddCar: car];

car =makeCar (@"Paper Car",@"Plymouth",@"Valiant",1965,2,76800,105);

[garageaddCar: car];

[garageprint];

NSNumber *count;

count = [garagevalueForKeyPath:@"cars.@count"];

NSLog (@"We have %@ cars", count);

NSNumber *sum;

sum = [garagevalueForKeyPath:@"cars.@sum.mileage"];

NSLog (@"We have a grand total of %@ miles", sum);

NSNumber *avgMileage;

avgMileage = [garagevalueForKeyPath:@"cars.@avg.mileage"];

NSLog (@"average is %.2f", [avgMileagefloatValue]);

NSNumber *min, *max;

min = [garagevalueForKeyPath:@"cars.@min.mileage"];

max = [garagevalueForKeyPath:@"cars.@max.mileage"];

NSLog (@"minimax: %@ / %@", min, max);

NSArray *manufacturers;

manufacturers = [garagevalueForKeyPath:@"cars.@distinctUnionOfObjects.make"];

NSLog (@"makers: %@", manufacturers);

car = [[garagevalueForKeyPath:@"cars"]lastObject];

NSArray *keys = [NSArrayarrayWithObjects:@"make",@"model",@"modelYear",nil];

NSDictionary *carValues = [car dictionaryWithValuesForKeys: keys];

NSLog (@"Car values : %@", carValues);

NSDictionary *newValues =

[NSDictionarydictionaryWithObjectsAndKeys:

@"Chevy",@"make",

@"Nova",@"model",

[NSNumbernumberWithInt:1964],@"modelYear",

[NSNullnull],@"mileage",

nil];

[carsetValuesForKeysWithDictionary: newValues];

NSLog (@"car with new values is %@", car);

[carsetValue:nilforKey:@"mileage"];

NSLog (@"Nil miles are %@", car.mileage);

[garagesetValue:@"bunny"forKey:@"fluffy"];

[garagesetValue:@"greeble"forKey:@"bork"];

[garagesetValue: [NSNullnull]forKey:@"snorgle"];

[garagesetValue:nilforKey:@"gronk"];

NSLog (@"values are %@ %@ %@ and %@",

  [garagevalueForKey:@"fluffy"],

  [garagevalueForKey:@"bork"],

  [garagevalueForKey:@"snorgle"],

     [garagevalueForKey:@"gronk"]);

NSLog (@"%@", [garagevalueForKey:@"stuff"]);

[garagerelease];

[poolrelease];

return (0);

} // main


8、输出结果

2013-01-09 09:01:05.408 16.02 Car-Value-Garaging[424:803] Joe's Garage:

2013-01-09 09:01:05.409 16.02 Car-Value-Garaging[424:803]     Herbie, a 1984 Honda CRX, has 2 doors, 110000.0 miles, 58 hp and 4 tires

2013-01-09 09:01:05.410 16.02 Car-Value-Garaging[424:803]     Badger, a 1987 Acura Integra, has 5 doors, 217036.7 miles, 130 hp and 4 tires

2013-01-09 09:01:05.411 16.02 Car-Value-Garaging[424:803]     Elvis, a 1989 Acura Legend, has 4 doors, 28123.4 miles, 151 hp and 4 tires

2013-01-09 09:01:05.411 16.02 Car-Value-Garaging[424:803]     Phoenix, a 1969 Pontiac Firebird, has 2 doors, 85128.3 miles, 345 hp and 4 tires

2013-01-09 09:01:05.412 16.02 Car-Value-Garaging[424:803]     Streaker, a 1950 Pontiac Silver Streak, has 2 doors, 39100.0 miles, 36 hp and 4 tires

2013-01-09 09:01:05.412 16.02 Car-Value-Garaging[424:803]     Judge, a 1969 Pontiac GTO, has 2 doors, 45132.2 miles, 370 hp and 4 tires

2013-01-09 09:01:05.413 16.02 Car-Value-Garaging[424:803]     Paper Car, a 1965 Plymouth Valiant, has 2 doors, 76800.0 miles, 105 hp and 4 tires

2013-01-09 09:01:05.414 16.02 Car-Value-Garaging[424:803] We have 7 cars

2013-01-09 09:01:05.414 16.02 Car-Value-Garaging[424:803] We have a grand total of 601320.6 miles

2013-01-09 09:01:05.415 16.02 Car-Value-Garaging[424:803] average is 85902.95

2013-01-09 09:01:05.415 16.02 Car-Value-Garaging[424:803] minimax: 28123.4 / 217036.7

2013-01-09 09:01:05.416 16.02 Car-Value-Garaging[424:803] makers: (

    Pontiac,

    Acura,

    Plymouth,

    Honda

)

2013-01-09 09:01:05.417 16.02 Car-Value-Garaging[424:803] Car values : {

    make = Plymouth;

    model = Valiant;

    modelYear = 1965;

}

2013-01-09 09:01:05.417 16.02 Car-Value-Garaging[424:803] car with new values is Paper Car, a 1964 Chevy Nova, has 2 doors, 0.0 miles, 105 hp and 4 tires

2013-01-09 09:01:05.418 16.02 Car-Value-Garaging[424:803] Nil miles are (null)

2013-01-09 09:01:05.418 16.02 Car-Value-Garaging[424:803] values are bunny greeble <null> and (null)

2013-01-09 09:01:05.419 16.02 Car-Value-Garaging[424:803] {

    bork = greeble;

    fluffy = bunny;

    snorgle = "<null>";

}








原创粉丝点击