首页 > 代码库 > 浅谈KAC

浅谈KAC

     今天我研究了一下KVC,下面我将浅谈一下我对KVC的认识,可能认识不足,我会在后续学习生活中改正.

首先,看到KVC,我们会想这个知识点是干嘛的,其实我们了解一下,就会发现KVC(Key-Value-Coding),键值编码 
KVC主要是用来间接访问实例变量(赋值)...

     下面我们看一下苹果给的KVC的官方文档:

/* Given a value and a key that identifies an attribute, set the value of the attribute. Given an object and a key that identifies a to-one relationship, relate the object to the receiver, unrelating the previously related object if there was one. Given a collection object and a key that identifies a to-many relationship, relate the objects contained in the collection to the receiver, unrelating previously related objects if there were any.


The default implementation of this method does the following:

    1. Searches the class of the receiver for an accessor method whose name matches the pattern -set<Key>:. If such a method is found the type of its parameter is checked. If the parameter type is not an object pointer type but the value is nil -setNilValueForKey: is invoked. The default implementation of -setNilValueForKey: raises an NSInvalidArgumentException, but you can override it in your application. Otherwise, if the type of the method‘s parameter is an object pointer type the method is simply invoked with the value as the argument. If the type of the method‘s parameter is some other type the inverse of the NSNumber/NSValue conversion done by -valueForKey: is performed before the method is invoked.

    2. Otherwise (no accessor method is found), if the receiver‘s class‘ +accessInstanceVariablesDirectly method returns YES, searches the class of the receiver for an instance variable whose name matches the pattern _<key>, _is<Key>, <key>, or is<Key>, in that order. If such an instance variable is found and its type is an object pointer type the value is retained and the result is set in the instance variable, after the instance variable‘s old value is first released. If the instance variable‘s type is some other type its value is set after the same sort of conversion from NSNumber or NSValue as in step 1.

    3. Otherwise (no accessor method or instance variable is found), invokes -setValue:forUndefinedKey:. The default implementation of -setValue:forUndefinedKey: raises an NSUndefinedKeyException, but you can override it in your application.

上面主要说的是

间接为变量赋值,当调用

setValue:  forKey:

或者

setValue: forKeyPath:

key用来标识实例变量

value实例变量对应的值

优先找_<key>, _is<Key>, <key>, or is<Key>,这个格式的实例变量,如果有的话,就直接赋值,如果没有就会产生异常

主要由两种异常,上面苹果文档也给出了解决方法.

第一:当key为非对象类型,且Value设置为nil的时候,会调用这个方法,系统是默认实现是抛出一个异常,我们可以重写这个方法,解决Value为nil的问题

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

- (void)setNilValueForKey:(NSString *)key

{

}

第二,当key不存在的时候,会调用这个方法,系统的默认实现是抛出一个异常,我们可以重写这个方法,解决key不存在的问题

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

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

{

}


然后在说说

setValue:  forKey:

或者

setValue: forKeyPath:

还有

setValuesForKeysWithDictionary: 

这三个方法的区别,

setValue:  forKey:  主要是间接为一个类中的单个实例变量赋值,如

[p setValue:@"张三"forKey:@"_name"];

setValue: forKeyPath:主要是间接的为一个类中,单个实例变量,这个实例变量也是一个类,然后这个类的实例变量赋值,下面的点      表示一个类中,实例变量,这个实例变量也是一个类,然后这个类的实例变量

[p setValue:@"哇哈哈"forKeyPath:@"a.name"];

setValuesForKeysWithDictionary:  主要是间接的为一个类中的所有实例变量赋值

[p setValuesForKeysWithDictionary:@{@"name":@"张三",@"age":@19,@"sex":@""}];


好了,今天就这些,如果上面看不懂,可以跟下面的代码一块看....


#import <Foundation/Foundation.h>
#import "A.h"
@interface Person : NSObject
{
    NSString * _name;
    NSInteger _age;
    A * _a;
}

- (instancetype)init;
- (void)saiHi;

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

#import "Person.h"

@implementation Person
- (void)saiHi
{
    NSLog(@"hello this is %@ %ld years old      ",_name,_age);
    [_a printName];
}

- (instancetype)init
{
    self = [super init];
    if (self) {
        _a = [[A alloc]init];
    }
    return self;
}
//当key为非对象类型,且value设置为nil的时候,会调用这个方法,系统的默认实现是抛出一个异常,我们可以重写这个方法,解决value为nil的问题
- (void)setNilValueForKey:(NSString *)key
{
    
}
//当key不存在的时候,会调用这个方法,系统的默认实现是抛出一个异常,我们可以重写这个方法,解决key不存在的问题
- (void)setValue:(id)value forUndefinedKey:(NSString *)key
{
    
}


@end

#import <Foundation/Foundation.h>

@interface A : NSObject
{
    NSString * _name;
    
}

- (void)printName;
@end

#import "A.h"

@implementation A
- (void)printName
{
    NSLog(@"%@",_name);
}

#import <Foundation/Foundation.h>
#import "Person.h"
int main(int argc, const char * argv[])
{
    
    //KVC 苹果脚本语言, 间接为变量赋值
    Person * p = [[Person alloc]init];
    [p setValue:@"张三" forKey:@"_name"];
//    [p valueForKey:@"账上"];
    [p setValue:@34 forKey:@"age"];
    
    [p setValue:@"男" forKey:@"sex"];
    //1.优先找setSex
    //2._sex
    //3._isSex
    //4.sex
    //5.isSex
    //如果没有,空,没有产生异常
    //可以重写解决异常
    
    //后期可以定义空类,加属性,定义一个万能的类
    
    
    
    //上面可以都不写
    
    [p setValuesForKeysWithDictionary:@{@"name": @"张三",@"age":@19,@"sex":@"男"}];
    
    
   
    
//    [p setValue:[a set] forKey:@"A"]
    //setValue: forKeyPath    可以给变量的变量的变量赋值
    [p setValue:@"哇哈哈" forKeyPath:@"a.name"];
    //当没有a的空间时,也没法给a赋值,
    //当把a开辟了空间,通过keyPath就可以赋值了
    [p saiHi];
    
    //处理空就写setNilValue方法就行了
    return 0;
}



发给客户