1、键值编码的基本概念和用法
键值编码的基本概念:
KVC是KeyValue Coding的简称,它是一种可以直接通过字符串的名字(key)来访问类属性的机制。使用该机制不需要调用存取方法和变量实例就可以访问对象属性。本质上讲,键-值编码定义了你的程序存取方法需要实现的样式及方法签名。
在应用程序中实现键-值编码兼容性是一项重要的设计原则。存取方法可以加强合适的数据封装,而键值编码方法在多数情况下可简化程序代码。
键-值 编码方法在Objective-c非标准协议 NSKeyValueCoding中被声明,默认的实现方法由NSObject提供。
键-值 编码支持带有对象值的属性,同时也支持纯数值类型和结构。非对象参数和返回值类型会被识别并自动封装/解封。
(KVC能访问类的私有变量类型)
2、其实由于ObjC的语言特性,你根部不必进行任何操作就可以进行属性的动态读写,这种方式就是Key Value Coding(简称KVC)。
KVC的操作方法由NSKeyValueCoding协议提供,而NSObject就实现了这个协议,也就是说ObjC中几乎所有的对象都支持KVC操作,常用的KVC操作方法如下:
• 动态设置: setValue:属性值 forKey:属性名(用于简单路径)、setValue:属性值 forKeyPath:属性路径(用于复合路径,例如Person有一个Account类型的属性,那么person.account就是一个复合属性)
• 动态读取: valueForKey:属性名 、valueForKeyPath:属性名(用于复合路径)
3、通过KVC为对象的属性变量设置值:
[对象 setValue:属性值 forKey:属性名];
此方法是非常智能的
(1)假如对象所对应的类中有与属性名相同的变量,就会直接对该变量赋值。
(2)若对应的类中没有与属性名相同的变量,此方法就会寻找前面带下划线属性名的变量,若有”_属性名”的变量就会对其赋值。若仍然没有的话就会报错。
(3)需要注意的是:若该设置方法的属性名带有下划线,则会直接在类中寻找相同属性名的变量对其赋值。但是若找不到的话,不会再去寻找去掉下划线后的属性变量。
(a. 此方法是NSKeyValueCoding协议中的方法,因为NSObject遵守了该协议,所以所有继承自根类NSObject的类的对象都可以直接调用此方法。
b. 此方法非常暴力:不管对象对应的类中相应变量是不是私有的都能一概访问对其赋值设置类对象的变量值
c. 通过KVC设值对象,此对象(被设置赋值即对象名作为键的对象)会被retain ,对象的引用计时器会自增。
d. 若对象对应类中为某变量提供了set方法,则使用此KVC方法对对象中的该变量赋值时会优先调用类中此变量的set方法进行赋值,若此变量没有set方法,则KVC方法直接对其变量赋值。get方法也与此类似。
)
4、通过KVC获取对象属性值
键值编码的基本概念:
KVC是KeyValue Coding的简称,它是一种可以直接通过字符串的名字(key)来访问类属性的机制。使用该机制不需要调用存取方法和变量实例就可以访问对象属性。本质上讲,键-值编码定义了你的程序存取方法需要实现的样式及方法签名。
在应用程序中实现键-值编码兼容性是一项重要的设计原则。存取方法可以加强合适的数据封装,而键值编码方法在多数情况下可简化程序代码。
键-值 编码方法在Objective-c非标准协议 NSKeyValueCoding中被声明,默认的实现方法由NSObject提供。
键-值 编码支持带有对象值的属性,同时也支持纯数值类型和结构。非对象参数和返回值类型会被识别并自动封装/解封。
(KVC能访问类的私有变量类型)
2、其实由于ObjC的语言特性,你根部不必进行任何操作就可以进行属性的动态读写,这种方式就是Key Value Coding(简称KVC)。
KVC的操作方法由NSKeyValueCoding协议提供,而NSObject就实现了这个协议,也就是说ObjC中几乎所有的对象都支持KVC操作,常用的KVC操作方法如下:
• 动态设置: setValue:属性值 forKey:属性名(用于简单路径)、setValue:属性值 forKeyPath:属性路径(用于复合路径,例如Person有一个Account类型的属性,那么person.account就是一个复合属性)
• 动态读取: valueForKey:属性名 、valueForKeyPath:属性名(用于复合路径)
3、通过KVC为对象的属性变量设置值:
[对象 setValue:属性值 forKey:属性名];
此方法是非常智能的
(1)假如对象所对应的类中有与属性名相同的变量,就会直接对该变量赋值。
(2)若对应的类中没有与属性名相同的变量,此方法就会寻找前面带下划线属性名的变量,若有”_属性名”的变量就会对其赋值。若仍然没有的话就会报错。
(3)需要注意的是:若该设置方法的属性名带有下划线,则会直接在类中寻找相同属性名的变量对其赋值。但是若找不到的话,不会再去寻找去掉下划线后的属性变量。
(a. 此方法是NSKeyValueCoding协议中的方法,因为NSObject遵守了该协议,所以所有继承自根类NSObject的类的对象都可以直接调用此方法。
b. 此方法非常暴力:不管对象对应的类中相应变量是不是私有的都能一概访问对其赋值设置类对象的变量值
c. 通过KVC设值对象,此对象(被设置赋值即对象名作为键的对象)会被retain ,对象的引用计时器会自增。
d. 若对象对应类中为某变量提供了set方法,则使用此KVC方法对对象中的该变量赋值时会优先调用类中此变量的set方法进行赋值,若此变量没有set方法,则KVC方法直接对其变量赋值。get方法也与此类似。
)
4、通过KVC获取对象属性值
[对象 valueForKey: 属性名];
新建OC工程具体代码如下:
新建一个空的Dog类
再建一个Person测试类 如下:
编辑Person.h如下:
//
// Person.h
// KVC的基本用法
//
// Created by apple on 15/9/20.
// Copyright (c) 2015年 LiuXun. All rights reserved.
//
#import <Foundation/Foundation.h>
@class Dog;
@interface Person : NSObject
{
@private
NSString *name;
@public
int _age;
Dog *dog;
}
-(void)setDog:(Dog *)dg;
@end
编辑Person.m如下:
//
// Person.m
// KVC的基本用法
//
// Created by apple on 15/9/20.
// Copyright (c) 2015年 LiuXun. All rights reserved.
//
#import "Person.h"
@implementation Person
-(NSString *)description
{
return [NSString stringWithFormat:@"name= %@ _age= %d",name, _age];
}
-(void)setDog:(Dog *)dg
{
if (dog!= dg) {
[dog release];
dog = [dg retain];
}
NSLog(@"setDog"); // 发现会调用dog的set方法
}
@end
编辑main.m如下:
//
// main.m
// KVC的基本用法
//
// Created by apple on 15/9/20.
// Copyright (c) 2015年 LiuXun. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "Person.h"
#import "Dog.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person *per = [[Person alloc] init];
[per setValue:@"LiuXun" forKey:@"name"]; //直接找到Person对象per的name变量对其赋值
[per setValue:@"22" forKey:@"age"]; // 先寻找age变量,没有找到。再找_age变量对其赋值
NSString *name = [per valueForKey:@"name"]; // KVC能直接访问(赋值或取值)对象的私有变量
NSLog(@"%d %@",per->_age, name);
NSLog(@"%@",per);
Dog *dog1 = [[Dog alloc] init];
NSLog(@"dog1 计数:%ld",dog1.retainCount);
[per setValue:dog1 forKey:@"dog"]; // 通过KVC设值此对象,此对象的引用计数器加一
NSLog(@"dog1 计数:%ld",dog1.retainCount);
[per release];
}
return 0;
}
运行结果如下: