KVC

来源:互联网 发布:sas编程 编辑:程序博客网 时间:2024/05/01 12:18

转自:http://www.cnblogs.com/kenshincui/p/3871178.html 崔江涛(KenshinCui)

概述

由于ObjC主要基于Smalltalk进行设计,因此它有很多类似于RubyPython的动态特性,例如动态类型、动态加载、动态绑定等。今天我们着重介绍ObjC中的键值编码(KVC)、键值监听(KVO)特性:

  1. 键值编码KVC
  2. 键值监听KVO

键值编码KVC

我们知道在C#中可以通过反射读写一个对象的属性,有时候这种方式特别方便,因为你可以利用字符串的方式去动态控制一个对象。其实由于ObjC的语言特性,你根部不必进行任何操作就可以进行属性的动态读写,这种方式就是Key Value Coding(简称KVC)。

KVC的操作方法由NSKeyValueCoding协议提供,而NSObject就实现了这个协议,也就是说ObjC中几乎所有的对象都支持KVC操作,常用的KVC操作方法如下:

  • 动态设置: setValue:属性值 forKey:属性名(用于简单路径)setValue:属性值 forKeyPath:属性路径(用于复合路径,例如Person有一个Account类型的属性,那么person.account就是一个复合属性) 
  • 动态读取: valueForKey:属性名 valueForKeyPath:属性名(用于复合路径)

下面通过一个例子来理解KVC

Account.h

//
//  Account.h
//  KVCAndKVO
//
//  Created by Kenshin Cui on14-2-16.
//  Copyright (c) 2014
Kenshin Cui. All rightsreserved.
//

#import<Foundation/Foundation.h>

@interfaceAccount :NSObject
#pragmamark -属性
#pragmamark余额
@
property(nonatomic,assign)floatbalance;
@end

Account.m

//
//  Account.m
//  KVCAndKVO
//
//  Created by Kenshin Cui on14-2-16.
//  Copyright (c) 2014
Kenshin Cui. All rightsreserved.
//

#import"Account.h"

@implementation Account

@end

Person.h

//
//  Person.h
//  KVCAndKVO
//
//  Created by Kenshin Cui on14-2-16.
//  Copyright (c) 2014
Kenshin Cui. All rightsreserved.
//

#import<Foundation/Foundation.h>
@classAccount;

@interfacePerson :NSObject{
    @
private
    int
_age;
}
#pragmamark -属性
#pragmamark姓名
@
property(nonatomic,copy)NSString *name;
#pragmamark账户
@
property(nonatomic,retain) Account*account;

#pragmamark -公共方法
#pragmamark显示人员信息
-(
void)showMessage;
@end

Person.m

//
//  Person.m
//  KVCAndKVO
//
//  Created by Kenshin Cui on14-2-16.
//  Copyright (c) 2014
Kenshin Cui. All rightsreserved.
//

#import"Person.h"

@implementation Person

#pragmamark -公共方法
#pragmamark显示人员信息
-(
void)showMessage{
    NSLog(@
"name=%@,age=%d",_name,_age);
}
@end

main.m

//
//  main.m
//  KVCAndKVO
//
//  Created by Kenshin Cui on14-2-16.
//  Copyright (c) 2014
Kenshin Cui. All rightsreserved.
//

#import<Foundation/Foundation.h>
#import "Person.h"
#import "Account.h"

intmain(intargc,const char* argv[]){
    @autoreleasepool {
       
        Person *person1=[[Personalloc]init];
        [person1setValue:@
"Kenshin"forKey:@"name"];
        [person1 setValue:@28 forKey:@
"age"];//注意即使一个私有变量仍然可以访问
       
       
[person1showMessage];
       
//结果:name=Kenshin,age=28
       
NSLog(@"person1'sname is :%@,age is :%@",person1.name,[person1 valueForKey:@"age"]);
       
//结果:person1's nameis :Kenshin,age is :28
       
       
       
       
       
Account *account1=[[Accountalloc]init];
        person1.account=account1;
//注意这一步一定要先给account属性赋值,否则下面按路径赋值无法成功,因为accountnil,当然这一步骤也可以写成:[person1setValue:account1 forKeyPath:@"account"];
       
       
[person1setValue:@100000000.0 forKeyPath:@"account.balance"];
       
        NSLog(@
"person1'sbalance is :%.2f",[[person1 valueForKeyPath:@"account.balance"]floatValue]);
       
//结果:person1'sbalance is :100000000.00
       
       
       
       
   
}
   
return0;
}

KVC使用起来比较简单,但是它如何查找一个属性进行读取呢?具体查找规则(假设现在要利用KVCa进行读取):

  • 如果是动态设置属性,则优先考虑调用setA方法,如果没有该方法则优先考虑搜索成员变量_a,如果仍然不存在则搜索成员变量a,如果最后仍然没搜索到则会调用这个类的setValue:forUndefinedKey:方法(注意搜索过程中不管这些方法、成员变量是私有的还是公共的都能正确设置) 
  • 如果是动态读取属性,则优先考虑调用a方法(属性agetter方法),如果没有搜索到则会优先搜索成员变量_a,如果仍然不存在则搜索成员变量a,如果最后仍然没搜索到则会调用这个类的valueforUndefinedKey:方法(注意搜索过程中不管这些方法、成员变量是私有的还是公共的都能正确读取)
0 0
原创粉丝点击