Object-C — KVC

1:使用kvc存取对象属性

如果要更改对象属性可以通过什么方法达到呢?

(1)通过setter和getter方法。

(2)属性。

(3)直接设置实例变量。

今天学习新的一种方法:键值编码-kvc。通过指定要访问的属性名字的字符串标识符,可以进行类的属性的读取和设置。

键值编码基本调用包括:setValue:forKey:和valueForKey。

栗子:

新建Student类,属性及成员变量:

@interface Student : NSObject
{
    @public
    NSString * name;
    @private
    NSString * hobby;
}
@property(strong,nonatomic) NSString * address;
@property(nonatomic) int age;
@end

通过setter和getter方法、属性可以设置属性:

    Student * stu1 = [Student new];
    stu1->name = @"haha";
    NSLog(@"%@",stu1->name);

    stu1.address = @"street";    //属性可通过点语法设置
    stu1.age = 100;
    NSLog(@"address:%@,age:%d",stu1.address,stu1.age);

***下边通过键值编码kvc设置***

    Student * stu1 = [Student new];
    [stu1 setValue:@"kvcName" forKey:@"name"];
    NSLog(@"kvc设置name:%@",[stu1 valueForKey:@"name"]);

    [stu1 setValue:@18 forKey:@"age"];  //int基本型的需要包装成oc对象型的
    NSLog(@"kvc设置age:%@",[stu1 valueForKey:@"age"]);

通过kvc也可以设置属性,甚至于private的成员变量也可以设置,Student类中有一个private的成员变量:hobby

    //private的属性仍然能够通过kvc设置,所以kvc破坏了面向对象的封装思想
    [stu1 setValue:@"read" forKey:@"hobby"];
    NSLog(@"%@",[stu1 valueForKey:@"hobby"]);

既然都可以设置属性,那么kvc和其他的有什么区别呢?它的使用场景是什么呢?

1:

key返回NSString类型的字符串。可以单独提出来:

    Student * stu1 = [Student new];
    NSString * key = @"name";  //变量 灵活
    //[stu1 setValue:@"kvcName" forKey:@"name"];
    [stu1 setValue:@"kvcName" forKey:key];
    NSLog(@"kvc设置name:%@",[stu1 valueForKey:@"name"]);

这样key相当于是一个中间变量,无疑大大增强了灵活性。

2:类似id型对象不能点语法的,那么可以通过kvc设置。如:

    id obj = stu1;    //id 不能通过点语法设置属性
    obj.name = @"hehe";    //报错
    [obj setValue:@"idName" forKey:@"name"];
    NSLog(@"id设置的name:%@",[obj valueForKey:@"name"]);

2:kvc特点:键搜索顺序

kvc首先查找的是setter命名的属性,为证实,重写setter,如果setter被调用则可以证实。

以Student的name成员变量为例,写setter方法:

- (void)setName:(NSString *)newName
{
    NSLog(@"kvc......");
    self->name = newName;
}

如果被调用则会打印kvc......,

main函数中:

    Student * stu1 = [Student new];
    NSString * key = @"name";
    [stu1 setValue:@"kvcName" forKey:key];
    NSLog(@"kvc设置name:%@",[stu1 valueForKey:@"name"]);

打印结果:

验证了。。。。。。如果不存在getter呢?也就是说不能用属性(属性会自动生成setter和getter方法),那么则会在对象内部查找_key或key的实例变量。

以Student的hobby为例,它不是属性,用没有写setter方法,现在声明hobby和_hobby,为了验证写了一个test方法:

@interface Student : NSObject
{
    @public
    NSString * name;
    @private
    NSString * hobby;
    NSString * _hobby;
}
@property(strong,nonatomic) NSString * address;
@property(nonatomic) int age;

- (void)test;

test方法:

- (void)test
{
    NSLog(@"_hobby = %@",self->_hobby);
    NSLog(@"hobby = %@",self->hobby);
}

那么当main中hobby通过kvc设置的时候,会发生什么?

    Student * stu1 = [Student new];
    [stu1 setValue:@"read" forKey:@"hobby"];
    [stu1 test];

按说这是给hobby设置值,打印结果:

结果_hobby上有值,这就证实kvc先查找_key。

注意:使用@[email protected]可以自动生成getter和setter,但是如果为其指定非标准的getter和setter,key的搜索则会出现问题。

2:键值编码的键路径

设想以下情况:添加一个Brother类,Student有一个属性是Brother对象。

@interface Student : NSObject
{
    @public
    NSString * name;
    @private
    NSString * hobby;
    NSString * _hobby;
}
@property(strong,nonatomic) NSString * address;
@property(nonatomic) int age;
//添加brother属性
@property(strong,nonatomic)Brother * brother;
- (void)setName:(NSString *)newName;

- (void)test;
@end

而Brother类下有一个属性broName。现在有这么一个需求:我需要通过Student给brother下的broName赋值。(不是通过brother)

那么代码似乎应该这么写:

    Student * stu1 = [Student new];
    Brother * bro1 = [Brother new];
    stu1.brother = bro1;
    [stu1 setValue:@"兄弟" forKey:@"bro1.broName"];
    NSLog(@"%@",[bro1 valueForKey:@"broName"]);      //崩溃

这么写代码崩溃,那该怎么写呢?使用键路径:setValue:forKeyPath:

假设a对象下有一个名为b的属性,而b中包含了名称为c的属性,如果想要从a获取(或设置)c属性的内容需要使用如下路径来描述: b.c (遇到点会解析成路径)

    Student * stu1 = [Student new];
    Brother * bro1 = [Brother new];
    stu1.brother = bro1;
    [stu1 setValue:@"兄弟" forKeyPath:@"brother.broName"];
    NSLog(@"%@",[stu1 valueForKeyPath:@"brother.broName"]);

这样就可以了,上面的代码稍作修改:现在brother下有一个brother对象brotherOld属性,该怎么赋值呢?

@interface Brother : NSObject
@property(strong,nonatomic) NSString * broName;
@property(strong,nonatomic) Brother * brotherOld;
@end

这样相当于通过两层去设置值。

    Student * stu1 = [Student new];
    Brother * bro1 = [Brother new];
    stu1.brother = bro1;

    Brother * bigBrother = [Brother new];
    bro1.brotherOld = bigBrother;
    [stu1 setValue:@"大兄弟" forKeyPath:@"brother.brotherOld.broName"];
    NSLog(@"%@",[stu1 valueForKeyPath:@"brother.brotherOld.broName"]);

3:键不存在的情况(了解即可)

为一个不存在的键setValue forKey的话,会报错,比如:

[stu1 setValue:@"mei you zhe ge jian" forKey:@"notExist"];    //崩溃

可以实现setValue:forUndefinedKey:

Student下声明一个字典:NSMutableDictionary * undefinedKeysAndValues可以存到这个字典中(相当于临时容器)

Student.m文件

//以下两个方法一般不重写
-(void)setValue:(id)value forUndefinedKey:(NSString *)key
{

    NSLog(@"呵呵,你所访问的键:%@不存在,你就别想把值:%@放到这个键上了,说的就跟你有这个键似的!",key,value);
    //[self->undefinedKeysAndValues setObject:value forKey:key];
}
-(id)valueForUndefinedKey:(NSString *)key
{
    NSLog(@"对不起,没有这样的键!");
    return nil;
    //return [self->undefinedKeysAndValues objectForKey:key];
}
@end

4:字典的valueForKey:

    NSDictionary * dict = @{@"aaa":@"11111111",@"bbb":@"22222222222"};
    //NSLog(@"%@",[dict objectForKey:@"aaa"]);
    NSLog(@"%@",[dict valueForKey:@"aaa"]);

打印结果:

2015-11-06 19:40:30.445 oc-kvc-001[846:61032] 11111111

Program ended with exit code: 0

本来字典的取值是通过objectForKey,现在也能通过valueForKey取值,说明valueForKey是NSobject的方法,字典继承自NSobject

5:操作集合

如果对象的某个实例变量为NSArray,而其中存放的又是对象。

Team.h文件:

@interface Team : NSObject
@property(strong,nonatomic) NSArray * members;
@end

Student.h文件:

@interface Student : NSObject
@property(copy,nonatomic) NSString * name;
@property(nonatomic) int age;
@end

Team下有一个属性为members的数组,members数组中存放的是Student对象。

        Student * s1 = [Student new];
        s1.name = @"学生甲";
        s1.age = 1000;

        Student * s2 = [Student new];
        s2.name = @"学生乙";
        s2.age = 28;

        Student * s3 = [Student new];
        s3.name = @"学生丙";
        s3.age = 1100;

        Student * s4 = [Student new];
        s4.name = @"学生丁";
        s4.age = 1400;

        NSArray * arr = @[s1,s2,s3,s4];

        //对NSArray请求一个键值,则会查询数组中的每一个对象来查找这个键,然后将这些结果重新打包为一个NSArray
        id ages = [arr valueForKey:@"age"];
        NSLog(@"%@",ages);
                //可以取最大值、最小值、求和、平均值、个数。
        id maxAge = [arr valueForKeyPath:@"@max.age"];
        id minAge = [arr valueForKeyPath:@"@min.age"];
        id sumAge = [arr valueForKeyPath:@"@sum.age"];
        id avgAge = [arr valueForKeyPath:@"@avg.age"];
        id count = [arr valueForKeyPath:@"@count"];
        NSLog(@"%@,%@,%@,%@,%@",maxAge,minAge,sumAge,avgAge,count);

        Team * team = [Team new];
        team.members = arr;

        maxAge = [team valueForKeyPath:@"[email protected]"];
        minAge = [team valueForKeyPath:@"[email protected]"];
        sumAge = [team  valueForKeyPath:@"[email protected]sum.age"];
        avgAge = [team  valueForKeyPath:@"[email protected]"];
        count = [team valueForKeyPath:@"[email protected]"];
        NSLog(@"%@,%@,%@,%@,%@",maxAge,minAge,sumAge,avgAge,count);

啊╮(╯▽╰)╭,结束。。。。。。。。

时间: 2024-10-06 07:58:53

Object-C — KVC的相关文章

走进 Realm 的世界

来源:XcodeMen(郭杰) 链接:http://www.jianshu.com/p/0e248f000405 本文由我们团队的郭杰童鞋分享. Realm是什么 Realm是由Y Combinator公司孵化出来的一款可以用于iOS(同样适用于Swift&Objective-C)和Android的跨平台移动数据库.历经几年才打造出来,为了彻底解决性能问题,核心数据引擎用C++打造,并不是建立在SQLite之上的ORM,所以Realm相比SQLite和CoreData而言更快.更好.更容易去使用

第10课: Storyboards

1. StroyBorad简介 Storyboards ios5引入 Single View Application模板创建工程Simple Storyboard 使用Use Storyboards 复选框 默认生成文件MainStoryboard.storyboard 一个应用程序委托 一个视图控制器类 sence(场景) The arrow points out which view controller is the initial view controller. 箭头指向第一个被初始化

Concurrent.Thread.js

(function(){ if ( !this.Data || (typeof this.Data != 'object' && typeof this.Data != 'function') ) this.Data = new Object(); if ( this.Data.Stack === undefined ) this.Data.Stack = undefined; with ( function(){ with ( Data ) { return function () {

0124——KVC KVO模式

1.KVC KVC是Key-Value-Coding的简称,它是一种可以直接通过字符串的名 字(key)来访问类属性(实例变量)的机制.而不是通过调用Setter.Getter方法访问.当使用KVO.Core Data.CocoaBindings.AppleScript(Mac支持)时,KVC是关键技术.  Person * xw = [[Person alloc]init]; Dog *dg = [[Dog alloc]init]; //使用kvc设置成员变量的值 //使用之前必须得知道变量的

iOS开发——实用篇&KVO与KVC详解

KVO与KVC详解 由于ObjC主要基于Smalltalk进行设计,因此它有很多类似于Ruby.Python的动态特性,例如动态类型.动态加载.动态绑定等.今天我们着重介绍ObjC中的键值编码(KVC).键值监听(KVO)特性: 键值编码KVC 键值监听KVO 键值编码KVC 我们知道在C#中可以通过反射读写一个对象的属性,有时候这种方式特别方便,因为你可以利用字符串的方式去动态控制一个对象.其实由于ObjC的语言特性,你根部不必进行任何操作就可以进行属性的动态读写,这种方式就是Key Valu

OC学习篇之---KVC和KVO操作

前一篇文章我们介绍了OC中最常用的文件操作:http://blog.csdn.net/jiangwei0910410003/article/details/41875015,那么今天来看一下OC中的一个比较有特色的知识点:KVC和KVO 一.KVC操作 OC中的KVC操作就和Java中使用反射机制去访问类的private权限的变量,很暴力的,这样做就会破坏类的封装性,本来类中的的private权限就是不希望外界去访问的,但是我们这样去操作,就会反其道而行,但是我们有时候真的需要去这样做,哎.所以

iOS 中KVC、KVO、NSNotification、delegate 总结及区别

iOS 中KVC.KVO.NSNotification.delegate 总结及区别 1.KVC,即是指 NSKeyValueCoding,一个非正式的Protocol,提供一种机制来间接访问对象的属性.而不是通过调用Setter.Getter方法访问.KVO 就是基于 KVC 实现的关键技术之一. Demo: @interface myPerson : NSObject { NSString*_name; int      _age; int      _height; int      _w

11. KVC And KVO

1. KVC And KVO  的认识 KVC/KVO是观察者模式的一种实现  KVC全称是Key-value coding,翻译成键值编码.顾名思义,在某种程度上跟map的关系匪浅.它提供了一种使用字符串而不是访问器方法去访问一个对象实例变量的机制.KVO全称是Key-value observing,翻译成键值观察.提供了一种当其它对象属性被修改的时候能通知当前对象的机制.再MVC大行其道的Cocoa中,KVO机制很适合实现model和controller类之间的通讯. 2. KVC And

iOS开发中KVC、KVO简介

在iOS开发中,KVC和KVO是经常被用到的.可以使用KVC对对象的属性赋值和取得对象的属性值,可以使用KVO监听对象属性值的变化.简单介绍一下KVC和KVO. 一:键值编码(KVC) KVC,全称 Key Value Coding(键值编码),是OC 语言的一个特性,使用KVC,可以对对象的属性进行动态读写. KVC的操作方法由 NSKeyValueCoding协议提供,而NSObject已经实现了这个协议,因此OC中的几乎所有对象都可以使用KVC操作.常用的KVC操作方法有: (1)设置属性

KVC 和KVO浅谈

一.KVC:Key-Value -Coding :直译为:键-值-代码:即:对键值进行改变的代码方法 该方法是OC(Object-C)为我们提供的一个不通过初始化方法而直接改变对象实例变量值的一种非正式Protocol的关键方法之一: 通过  [object setValue : value forKey : key];对该对象的对应的实例变量进行赋值操作,省略了初试化步奏,使用得当可以大大省略代码量: 二.KVO:Key-Value - Observe :直译为:键-值-观察:即:对键值对进行