• KVC介绍



    1. Key Value Coding(键值编码)

    最基本的KVC由NSKeyValueCoding协议支持,最基本的操作由以下几个完成:

    • -(id)valueForKey:(NSString *)key;
    • -(void)setValue:(id)value forKey:(NSString *)key;
    • -(id)valueForKeyPath:(NSString *)keyPath;
    • -(void)setValue:(id)value forKeyPath:(NSString *)keyPath;

    1.1 简单使用KVC,KVC的执行机制

    例如一个类:

    #import <Foundation/Foundation.h>
    
    @interface FKUser : NSObject
    // 使用@property定义3个property
    @property (nonatomic, copy) NSString* name;
    @property (nonatomic, copy) NSString* pass;
    @property (nonatomic, copy) NSDate* birth;
    @end
    

    使用kvc:

    #import "FKUser.h"
    
    int main(int argc , char * argv[])
    {
    @autoreleasepool{
    	// 创建FKUser对象
    	FKUser* user = [[FKUser alloc] init];
    	// 使用KVC方式为name属性设置属性值
    	[user setValue:@"孙悟空" forKey:@"name"];
    	// 使用KVC方式为pass属性设置属性值	
    	[user setValue:@"1455" forKey:@"pass"];
    	// 使用KVC方式为birth属性设置属性值
    	[user setValue:[[NSDate alloc]init] forKey:@"birth"];
    	// 使用KVC获取FKUser对象的属性
    	NSLog(@"user的name为:%@" , [user valueForKey:@"name"]);
    	NSLog(@"user的pass为:%@" , [user valueForKey:@"pass"]);
    	NSLog(@"user的birth为:%@" , [user valueForKey:@"birth"]);
    }
    }	
    

    对于 [user setValue:@"孙悟空" forKey:@"name"];执行的机制如下:

    1. 优先考虑调用属性的set方法,即setName
    2. 若是该类没有对应的set方法,KVC会搜索该类名为_name,无论_name是在类接口部分定义,还是在类实现部分定义也无论用哪个访问控制符修饰,然后对_name成员变量赋值
    3. 如果该类既没有setName:方法,也没有_name成员变量,KVC会搜索名为name的成员变量,然后对name成员变量赋值
    4. 若是以上3条都没有找到,会执行对象的setValue:forUndefineKey方法,默认这个方法会引起异常导致程序结束

    对于[user valueForKey:@"name"],执行的机制如下:

    1. 优先考虑调用name的get方法
    2. 若该类没有name的get方法,KVC机制会搜索该类_name的成员变量
    3. 若还是找不到,则搜索name的成员变量
    4. 最后若还是找不到,执行valueforUndefinedKey方法

    1.2 处理不存在的key

    重写一下两个方法就可以了。

    - (void) setValue:(id)value forUndefinedKey:(id)key
    {
    NSLog(@"您尝试设置的key:【%@】并不存在!", key);
    NSLog(@"您尝试设置的value为:%@", value);
    }
    - (void) valueForUndefinedKey:(id)key
    {
    NSLog(@"您尝试访问的key:【%@】并不存在!", key);
    }
    

    1.3 处理nil

    当对基本类型数据使用kvc赋值为nil时也会出错,程序员抛出NSInvalidArgumentException

    这时候需要重写如下方法:

    - (void)setNilValueForKey: (id)key
    {
    // 如果尝试将key为price的属性设为nil
    if([key isEqualToString:@"price"])
    {
    	// 将该price设置为0
    	price = 0;
    }
    else
    {
    	// 回调父类的setNilValueForKey,执行默认行为
    	[super setNilValueForKey: key];
    }
    }	
    

    1.4 简单使用key路径

    直接给代码吧:

    FKItem.h文件:

    #import <Foundation/Foundation.h>
    
    @interface FKItem : NSObject
    // 使用@property定义两个属性
    @property(nonatomic , copy) NSString* name;
    @property(nonatomic , assign) int price;
    @end	
    

    FKOrder.h文件:

    #import <Foundation/Foundation.h>
    #import "FKItem.h"
    
    @interface FKOrder : NSObject
    // 使用@property定义两个属性
    @property(nonatomic , strong) FKItem* item;
    @property(nonatomic , assign) int amount;
    -(int) totalPrice;
    @end	
    

    使用:

    int main(int argc , char * argv[])
    {
    @autoreleasepool{
    	// 创建FKItem对象
    	FKOrder* order = [[FKOrder alloc] init];
    	// 使用KVC方式为amount设置属性值
    	[order setValue:@"12" forKey:@"amount"];
    	[order setValue:[[FKItem alloc] init] forKey:@"item"];
    	// 使用setValue:forKeyPath设置item属性的name属性
    	[order setValue:@"鼠标" forKeyPath:@"item.name"];
    	// 使用valueForKeyPath来获取复合属性值
    	[order setValue:[NSNumber numberWithInt:20] forKeyPath:@"item.price"];
    	NSLog(@"订单包含%@个%@,总价为:%@", [order valueForKey:@"amount"] , 
    		[order valueForKeyPath:@"item.name"],
    		[order valueForKey:@"totalPrice"]);
    }
    }	
    

    1.5 使用key路径聚合信息

    使用 @count 、@sum、@avg、@min、@max、@distinctUnionOfObject获取对象数组中的聚合信息

    一般形式为:

    [keypath].[@operator].[property name]
    

    例如

    id sum = [workProject01 valueForKeyPath:@"listOfTasks.@sum.priority"];
    

    listOfTasks 是 Task对象的数组,每个Task对象都有名为priority的int类型属性

  • 相关阅读:
    Count Up Down(上下计数)
    TCP与UDP的区别
    xml和json的区别
    java中String,StringBuffer,StringBuilder的区别
    java中访问修饰符public,private,protected,friendly的作用域
    java中的数据类型,基本数据类型及其包装类型
    Collection和Collections的区别
    Java中静态变量和实例变量的区别
    Java中实现多态的条件是什么
    Java中抽象类和接口的区别
  • 原文地址:https://www.cnblogs.com/sunyanyan/p/5408303.html
Copyright © 2020-2023  润新知