KVC(键值编码)(二十五)

kvc的英文全称是key-value-coding,意思就是键值对编码。用普通的话来说,就是kvc就是通过使用键(字符串)来取值的一种编码。是一种间接访问对象属性的机制,不需要调用getter、setter这些存取方法,就可以直接访问对象属性。

我们声明的变量,有可见度。有些私有的,或者受保护的变量,在其他类中,不能直接使用。我们可以通过kvc,用对象在类外部对实例变量进行访问和赋值。不论是什么可见度的实例变量(private,protected,public)。

setValue: forKey:

setValue:@”1111” forKey:@”name”。以此来举例说明,我们的key为name,此时,对象在调用这个方法的时候,会去找我们的声明中,有没有这个name对应的变量或者属性(名字必须是name或者_name)。否则会导致程序找不到匹配的变量,崩溃。

这个方法,优先调用setter方法,即setXxx这种格式的方法,这个set后的Xxx转换成小写后,就可以作为这个key。

如果这时候,找不到匹配的setter方法,就会去找实例变量,并且自动匹配下划线 _ 。(我们在key中加不加下划线 _ 都可以)。如果两者都找不到,就会崩溃。

Person.h

#import <Foundation/Foundation.h>

@interface Person : NSObject{

    @private

    NSString *_name;

   

    NSString *_sex;

}

 

- (void)sayHi;

@end

 

 

 

 

 

Person.m

#import "Person.h"

 

@implementation Person

- (void)sayHi{

    NSLog(@"%@",_name);

}

@end

main.m

#import <Foundation/Foundation.h>

#import "Person.h"

int main(int argc, const char * argv[]) {

    @autoreleasepool {

        Person *p1 = [[Person alloc]init];   

 //setValue:forKey:

        //优先调用setter方法,即:setXxx:,这个set后面的 Xxx 就可以作为key。

        //其次,set方法没有找到,就去找实例变量。并且自动识别下划线。(我们在key里加不加下划线都可以识别名字)。如果名字不一样,崩溃

        p1->_name;

        //kvc第一个方法:

        [p1 setValue:@"123" forKey:@"name"];

        NSLog(@"%@",[p1 valueForKey:@"name"]);

    }

    return 0;

}

解释:

[p1 setValue:@"123" forKey:@"name"];p1在设置key为name的变量的值为“123”,此时就回去找setter方法,发现没有定义setter方法,就回去实例变量中匹配,发现有一个_name,与之匹配,则对 _name进行赋值。

valueForKey:用键取值

 

通过键来取value,优先调用getter方法,取值,即形如我们定义的getter方法的方法xxx,((返回值)方法名,这样的方法就是形如getter方法。方法名就作为key),如实没有找到getter方法,就会去找实例变量,并能识别下划线 _。

NSLog(@"%@",[p1 valueForKey:@"name"]);

解释:去找name的getter方法,发现没找到,就去找实例变量,匹配到了,就可以取到值。

valueForKey:不仅可以取到变量值,还能用方法名作为key去找一个方法,然后执行。

 

 

Person.h

#import <Foundation/Foundation.h>

 

@interface Person : NSObject{

    @private

    NSString *_name;

   

    NSString *_sex;

}

- (void)sayHi;

@end

Person.m

 

#import "Person.h"

@implementation Person

- (void)sayHi{

    NSLog(@"%@",_name);

}

 

- (void)setLol:(NSString *)lol{

    NSLog(@"%@",lol);

}

//没有找到对应key

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

    NSLog(@"没有key:%@,value:%@",key,value);

}

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

    NSLog(@"没有 key :%@",key);

    return nil;

}

@end

main.m

        [p1 sayHi];

        [p1 valueForKey:@"sayHi"];

       

        [p1 setValue:@"德玛西亚" forKey:@"Lol"];//2015-04-22 16:08:00.048 OClesson8_KVC[2113:121073] 德玛西亚

解释:

在.h中声明了sayHi方法,在.m中实现sayHi,此时在main函数中用p1对象调用valueForKey:@"sayHi",就会把这个sayHi字符串去匹配,发现匹配了一个方法,此时就会去调用这个方法,执行。

在.m中实现了Lol:这个方法,在main方法中,对象p1调用了setValue:@"德玛西亚" forKey:@"Lol"方法,就把Lol作为key去匹配,发现匹配了setLol:方法,此时就会把value当作参数传进去,执行setLol:方法。

从父类继承过来的私有,受保护的实例变量,也可以用kvc访问。

setValue: forKeyPath:按照路径设置值

valueForKeyPath: 按照路径取值

若实例变量中有我们自定义的类,这个自定义的类中有另外的实例变量。此时要想访问实例变量为自定义类中的实例变量,就需要kvc按路径访问。

setValue:forUndefinedKey:设置值匹配不到key的处理

valueForUndefinedKey: 取值匹配不到key的处理

如果在按key访问变量或方法的时候,匹配不到所给的字符串(也就是key),需要加上setValue:forUndefinedKey(设置值)或者valueForUndefinedKey(取值)进行相应的处理,防止程序崩掉。

setValuesForKeysWithDictionary:按字典设置值

当有很多个值得时候,我们可以一次性赋值,就是用字典来赋值。

Person.h(父类)

#import <Foundation/Foundation.h>

 

@interface Person : NSObject{

    @private

    NSString *_name;

   

    NSString *_sex;

}

- (void)sayHi;

@end

Person.m(父类实现)

#import "Person.h"

@implementation Person

- (void)sayHi{

    NSLog(@"%@",_name);

}

- (void)setLol:(NSString *)lol{

    NSLog(@"%@",lol);

}

//没有找到对应key

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

    NSLog(@"没有key:%@,value:%@",key,value);

}

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

    NSLog(@"没有 key :%@",key);

    return nil;

}

 

@end

Student.h(继承于Person类)

#import "Person.h"

@class Book;

@interface Student : Person{

    Book *_book;

}

@end

Student.m

#import "Student.h"

#import "Book.h"

@implementation Student

 

@end

Book.h(继承于Student类)

#import <Foundation/Foundation.h>

@interface Book : NSObject{

    NSString *_bookName;

}

@end

Book.m

#import "Book.h"

 

@implementation Book

 

@end

main.m

 

#import <Foundation/Foundation.h>

#import "Person.h"

#import "Student.h"

#import "Book.h"

int main(int argc, const char * argv[]) {

    @autoreleasepool {

        Person *p1 = [[Person alloc]init];

       

        Student *s1 = [[Student alloc]init];

        //从父类继承的私有实例变量,也可以用kvc访问。

        [s1 setValue:@"22222" forKey:@"name"];

       

        NSLog(@"%@",[s1 valueForKey:@"name"]);//2015-04-22 16:21:33.162 OClesson8_KVC[2186:125614] 22222

      

        Student *s2 = [[Student alloc]init];

        Book *b1 = [[Book alloc]init];

//        [b1 setValue:@"红楼梦" forKey:@"bookName"];

        [s2 setValue:b1 forKey:@"book"];

        [s2 setValue:@"红楼梦" forKeyPath:@"book.bookName"];//点 . 不是点语法,是路径的意思。

       

        NSLog(@"%@",[s2 valueForKeyPath:@"book.bookName"]);//2015-04-22 16:32:49.975 OClesson8_KVC[2236:129639] 红楼梦

       

//      //设置值没有对应的key,在person.m中写一个undifind 

//    [p1 setValue:@"12131313" forKeyPath:@"num"];//2015-04-22 16:54:24.955 OClesson8_KVC[2324:135915] 没有key:num,value:12131313

//        //取值没有对应的key,在person.m中写一个undifind

//        [p1 valueForKeyPath:@"num"];//2015-04-22 16:56:22.108 OClesson8_KVC[2348:136844] 没有 key :num

       

        NSDictionary *dict = @{@"name":@"Mick",@"sex":@"男"};

        //一次性赋多个值,在网络解析中常用。

        [p1 setValuesForKeysWithDictionary:dict];

    }

    return 0;

}

posted @ 2016-01-10 16:11  恒远也  阅读(505)  评论(0编辑  收藏  举报