首页 > 代码库 > KVC方法详解与实现原理
KVC方法详解与实现原理
KVC提供了一种在运行时而非编译时动态访问对象属性与成员变量的方式,该方法不需要调用get和set方法和变量实例就可以访问对象,KVC默认的实现方法有NSOject提供,这种方法及支持对象也支持简单数据类型。
第一、在OC中访问变量的几种方式:
1、设置为public型,通过->直接访问:
代码为:
@interface Book : NSObject
{
@public
NSString *name;
}
Book *book=[[Bookalloc]init];
book->name=@"hello";
NSLog(@"val is %@",book->name);
2.利用属性访问
3.利用KVC,即使该属性是private也可以访问
@interface Book : NSObject
{
@private
NSString *name;
}
Book *book=[[Book alloc]init];
[book setValue:@"hello"forKey:@"name"];
NSLog(@"val is %@",[bookvalueForKey:@"name"]);
第二、KVC路径访问
除了通过键设置值外,键/值编码还支持指定路径,像文件系统一样,用“点”号隔开
[book valueForKeyPath:@"authorObj.name"]
sample:
Book *book=[[Book alloc] init];
[book setValue:@"hello" forKey:@"name"];
NSLog(@"val is %@",[book valueForKey:@"name"]);
author *authorObj=[[author alloc] init];
[authorObj setValue:@"niudun" forKey:@"name"];
[book setValue:authorObj forKey:@"authorObj"];
NSLog(@"the author of book is%@",[book valueForKeyPath:@"authorObj.name"]);
第三、一对多
@interface Book : NSObject
{
@private
NSString *name;
author *authorObj;
NSArray *relativeBooks;
} //kvc
Book *book=[[Book alloc] init];
[book setValue:@"hello" forKey:@"name"];
NSLog(@"val is %@",[book valueForKey:@"name"]);
//keypath
author *authorObj=[[author alloc] init];
[authorObj setValue:@"niudun" forKey:@"name"];
[book setValue:authorObj forKey:@"authorObj"];
NSLog(@"the author of book is%@",[book valueForKeyPath:@"authorObj.name"]);
//一对多
NSMutableArray *array=[NSMutableArray arrayWithCapacity:3];
for (int i=0; i<3; i++) {
Book *bookObj=[[Book alloc] init];
NSString *name=[NSString stringWithFormat:@"job_%d",i];
[bookObj setValue:name forKey:@"name"];
[array addObject:bookObj];
[bookObj release];
}
[book setValue:array forKey:@"relativeBooks"];
NSArray *arr=[book valueForKeyPath:@"relativeBooks.name"];
NSLog(@"arr is %@",arr);
第四、kvc支持简单的预算如max、min、sum,其中运算的字段必须是基本数据类型或NSNumber类型
第五、KVC对数值和结构体类型的支持
一套机制如果不支持数值和结构体型的数据,那么它的实用性就会大大折扣。幸运的是KVC中苹果对这方面的支持做的很好。KVC可以自动的将数值或结构体型的数据打包或解包成NSNumber或NSValue对象,以达到适配的目的。
举个例子,Person类有个个NSInteger类型的num属性
①修改值
我们通过KVC技术使用如下方式设置age属性的值:
[_person setValue:[NSNumber numberWithInteger:5] forKey:@"num"];
我们赋给num的是一个NSNumber对象,KVC会自动的将NSNumber对象转换成NSInteger对象,然后再调用相应的访问器方法设置age的值。
②获取值
同样,以如下方式获取age属性值:
[person valueForKey:@"num"];
这时,会以NSNumber的形式返回num的值。
第六、KVC实现原理的方法定义
在iOS中,通过KVC可以直接用字符串的名字(key)来访问类属性的机制。而不是通过调用Setter、Getter方法访问。
KVC是KVO、Core Data、CocoaBindings的技术基础,他们都是利用了OC的动态性。
NSKeyValueCodingprotocol
第七、setValue:forKey是如何访问属性值的
KVC方法的实现get、set方法及实例变量的访问,KVC setValue方法和getValue方法按顺序使用如下技术:
1. 检查是否存在set<Key>:方法
如果成员用@property,@synthsize处理,因为@synthsize告诉编译器自动生成set<Key>:格式的set方法,所以这种情况下会直接搜索到。
2. 检查名为-_<key>、-_is<key>(只针对布尔值有效)、-_set<key>:方法;
那么按_<key>,_is<Key>,<key>,is<key>的顺序搜索成员名。
3. 直接访问实例变量。实例变量可以是名为:<key>或_<key>;
4. 调用方法setValue:forUndefinedKey
第八、valueForKey是如何访问属性值的
跟上面setValue执行顺序类似,把set方法改成get方法,当所有都失效时调用方法valueForUndefinedKey。
第九、方法重写
如果我们的类既没有key或_key对应的set/get方法,也没有key或_key对应的实例变量,但要使用setValue和getValue方法,必须重写函数setValue:forUndefinedKey和valueForUndefinedKey。
在这儿我们可以利用OC的关联机制
1.什么是关联机制
OC提供了两种共享机制,一种是category,一种是associative,category只能扩展方法,associative可以扩展属性。
关联机制是基于关键字的,我们可以为任何对象增加任意多的关联,每个都使用不同的关键字即可。关联是可以保证被关联的对象在关联对象的整个生命周期都是可用的(在垃圾自动回收环境下也不会导致资源不可回收)。使用关联机制必须引入<objc/runtime.h>头文件
2.objc_setAssociatedObject创建关联
OBJC_EXPORT void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_1);
objc_setAssociatedObject来把一个对象与另外一个对象进行关联。该函数需要四个参数:源对象,关键字,关联的对象和一个关联策略
参数说明:
object:表示源对象
key:关键词
value:表示关联的对象
policy:关联策略,关联策略表明了相关的对象是通过赋值,保留引用还是复制的方式进行关联的;还有这种关联是原子的还是非原子的。这里的关联策略和声明属性时的很类似。
policy有四个值:
OBJC_ASSOCIATION_ASSIGN = 0, /**< Specifies a weak reference to the associated object. */
OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, /**< Specifies a strong reference to the associated object.
* The association is not made atomically. */
OBJC_ASSOCIATION_COPY_NONATOMIC = 3, /**< Specifies that the associated object is copied.
* The association is not made atomically. */
OBJC_ASSOCIATION_RETAIN = 01401, /**< Specifies a strong reference to the associated object.
* The association is made atomically. */
OBJC_ASSOCIATION_COPY = 01403 /**< Specifies that the associated object is copied.
* The association is made atomically. */
3. objc_getAssociatedObject获取关联对象
OBJC_EXPORT id objc_getAssociatedObject(id object, const void *key)
__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_1);
4.objc_removeAssociatedObjects删除该对象的所有关联,通常情况下不建议使用这个函数,因为他会断开所有关联。只有在需要把对象恢复到“原始状态”的时候才会使用这个函数。
OBJC_EXPORT void objc_removeAssociatedObjects(id object)
__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_1);
NSArray *arr=[NSArray arrayWithObjects:@"one",nil];
objc_setAssociatedObject(arr, @"hello", @"world", OBJC_ASSOCIATION_RETAIN);
NSString *ret=(NSString *)objc_getAssociatedObject(arr, @"hello");
NSLog(@"the result is %@",ret);
5. objc_setAssociatedObject with nil 来断开指定key得关联
6. 重写方法的实现
- (void)setValue:(id)value forUndefinedKey:(NSString *)key {
if (value =http://www.mamicode.com/= nil) {
value = http://www.mamicode.com/[NSNull null];
}
objc_setAssociatedObject(self, (__bridge const void *)(key), value, OBJC_ASSOCIATION_RETAIN);
}
- (id)valueForUndefinedKey:(NSString *)key {
id target = objc_getAssociatedObject(self, (__bridge const void *)(key));
if ([target isKindOfClass:[NSNull class]])
return nil;
return target;
}
第一、在OC中访问变量的几种方式:
1、设置为public型,通过->直接访问:
代码为:
@interface Book : NSObject
{
@public
NSString *name;
}
Book *book=[[Bookalloc]init];
book->name=@"hello";
NSLog(@"val is %@",book->name);
2.利用属性访问
3.利用KVC,即使该属性是private也可以访问
@interface Book : NSObject
{
@private
NSString *name;
}
Book *book=[[Book alloc]init];
[book setValue:@"hello"forKey:@"name"];
NSLog(@"val is %@",[bookvalueForKey:@"name"]);
第二、KVC路径访问
除了通过键设置值外,键/值编码还支持指定路径,像文件系统一样,用“点”号隔开
[book valueForKeyPath:@"authorObj.name"]
sample:
Book *book=[[Book alloc] init];
[book setValue:@"hello" forKey:@"name"];
NSLog(@"val is %@",[book valueForKey:@"name"]);
author *authorObj=[[author alloc] init];
[authorObj setValue:@"niudun" forKey:@"name"];
[book setValue:authorObj forKey:@"authorObj"];
NSLog(@"the author of book is%@",[book valueForKeyPath:@"authorObj.name"]);
第三、一对多
@interface Book : NSObject
{
@private
NSString *name;
author *authorObj;
NSArray *relativeBooks;
} //kvc
Book *book=[[Book alloc] init];
[book setValue:@"hello" forKey:@"name"];
NSLog(@"val is %@",[book valueForKey:@"name"]);
//keypath
author *authorObj=[[author alloc] init];
[authorObj setValue:@"niudun" forKey:@"name"];
[book setValue:authorObj forKey:@"authorObj"];
NSLog(@"the author of book is%@",[book valueForKeyPath:@"authorObj.name"]);
//一对多
NSMutableArray *array=[NSMutableArray arrayWithCapacity:3];
for (int i=0; i<3; i++) {
Book *bookObj=[[Book alloc] init];
NSString *name=[NSString stringWithFormat:@"job_%d",i];
[bookObj setValue:name forKey:@"name"];
[array addObject:bookObj];
[bookObj release];
}
[book setValue:array forKey:@"relativeBooks"];
NSArray *arr=[book valueForKeyPath:@"relativeBooks.name"];
NSLog(@"arr is %@",arr);
第四、kvc支持简单的预算如max、min、sum,其中运算的字段必须是基本数据类型或NSNumber类型
第五、KVC对数值和结构体类型的支持
一套机制如果不支持数值和结构体型的数据,那么它的实用性就会大大折扣。幸运的是KVC中苹果对这方面的支持做的很好。KVC可以自动的将数值或结构体型的数据打包或解包成NSNumber或NSValue对象,以达到适配的目的。
举个例子,Person类有个个NSInteger类型的num属性
①修改值
我们通过KVC技术使用如下方式设置age属性的值:
[_person setValue:[NSNumber numberWithInteger:5] forKey:@"num"];
我们赋给num的是一个NSNumber对象,KVC会自动的将NSNumber对象转换成NSInteger对象,然后再调用相应的访问器方法设置age的值。
②获取值
同样,以如下方式获取age属性值:
[person valueForKey:@"num"];
这时,会以NSNumber的形式返回num的值。
第六、KVC实现原理的方法定义
在iOS中,通过KVC可以直接用字符串的名字(key)来访问类属性的机制。而不是通过调用Setter、Getter方法访问。
KVC是KVO、Core Data、CocoaBindings的技术基础,他们都是利用了OC的动态性。
NSKeyValueCodingprotocol
第七、setValue:forKey是如何访问属性值的
KVC方法的实现get、set方法及实例变量的访问,KVC setValue方法和getValue方法按顺序使用如下技术:
1. 检查是否存在set<Key>:方法
如果成员用@property,@synthsize处理,因为@synthsize告诉编译器自动生成set<Key>:格式的set方法,所以这种情况下会直接搜索到。
2. 检查名为-_<key>、-_is<key>(只针对布尔值有效)、-_set<key>:方法;
那么按_<key>,_is<Key>,<key>,is<key>的顺序搜索成员名。
3. 直接访问实例变量。实例变量可以是名为:<key>或_<key>;
4. 调用方法setValue:forUndefinedKey
第八、valueForKey是如何访问属性值的
跟上面setValue执行顺序类似,把set方法改成get方法,当所有都失效时调用方法valueForUndefinedKey。
第九、方法重写
如果我们的类既没有key或_key对应的set/get方法,也没有key或_key对应的实例变量,但要使用setValue和getValue方法,必须重写函数setValue:forUndefinedKey和valueForUndefinedKey。
在这儿我们可以利用OC的关联机制
1.什么是关联机制
OC提供了两种共享机制,一种是category,一种是associative,category只能扩展方法,associative可以扩展属性。
关联机制是基于关键字的,我们可以为任何对象增加任意多的关联,每个都使用不同的关键字即可。关联是可以保证被关联的对象在关联对象的整个生命周期都是可用的(在垃圾自动回收环境下也不会导致资源不可回收)。使用关联机制必须引入<objc/runtime.h>头文件
2.objc_setAssociatedObject创建关联
OBJC_EXPORT void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_1);
objc_setAssociatedObject来把一个对象与另外一个对象进行关联。该函数需要四个参数:源对象,关键字,关联的对象和一个关联策略
参数说明:
object:表示源对象
key:关键词
value:表示关联的对象
policy:关联策略,关联策略表明了相关的对象是通过赋值,保留引用还是复制的方式进行关联的;还有这种关联是原子的还是非原子的。这里的关联策略和声明属性时的很类似。
policy有四个值:
OBJC_ASSOCIATION_ASSIGN = 0, /**< Specifies a weak reference to the associated object. */
OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, /**< Specifies a strong reference to the associated object.
* The association is not made atomically. */
OBJC_ASSOCIATION_COPY_NONATOMIC = 3, /**< Specifies that the associated object is copied.
* The association is not made atomically. */
OBJC_ASSOCIATION_RETAIN = 01401, /**< Specifies a strong reference to the associated object.
* The association is made atomically. */
OBJC_ASSOCIATION_COPY = 01403 /**< Specifies that the associated object is copied.
* The association is made atomically. */
3. objc_getAssociatedObject获取关联对象
OBJC_EXPORT id objc_getAssociatedObject(id object, const void *key)
__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_1);
4.objc_removeAssociatedObjects删除该对象的所有关联,通常情况下不建议使用这个函数,因为他会断开所有关联。只有在需要把对象恢复到“原始状态”的时候才会使用这个函数。
OBJC_EXPORT void objc_removeAssociatedObjects(id object)
__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_1);
NSArray *arr=[NSArray arrayWithObjects:@"one",nil];
objc_setAssociatedObject(arr, @"hello", @"world", OBJC_ASSOCIATION_RETAIN);
NSString *ret=(NSString *)objc_getAssociatedObject(arr, @"hello");
NSLog(@"the result is %@",ret);
5. objc_setAssociatedObject with nil 来断开指定key得关联
6. 重写方法的实现
- (void)setValue:(id)value forUndefinedKey:(NSString *)key {
if (value =http://www.mamicode.com/= nil) {
value = http://www.mamicode.com/[NSNull null];
}
objc_setAssociatedObject(self, (__bridge const void *)(key), value, OBJC_ASSOCIATION_RETAIN);
}
- (id)valueForUndefinedKey:(NSString *)key {
id target = objc_getAssociatedObject(self, (__bridge const void *)(key));
if ([target isKindOfClass:[NSNull class]])
return nil;
return target;
}
KVC方法详解与实现原理
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。