KVC 和 KVO
1. KVC(key value coding)
1.1. 基本概念
1> 我们一般是通过set方法或者属性的点语法来直接更改对象的状态,即对象的属性值,比如[stu setAge:29]; stu.age = 30;
2> KVC 它是以间接更改对象状态的方式,其实现方法是使用字符串来描述对象需要更改的属性。KVC中经常调用的方法包括valueForKey:和setVale:forKey:,以字符串的方式想对象发送消息。
1.2. 键路径(Key Path)
1> 除了通过键设置值外,KVC还支持键路径,像文件系统路径一样,其实就是属性的链式访问。
2> 比如:利用键路径设置Student对象中Card对象的no属性,语法形式如下:
[student setValue:@"123456" forKeyPath:@"card.no"];
3> 获取Student对象中Card对象的no,其语法形式如下:
[student valueForKeyPath:@"card.no"];
1.3. 数组的整体操作
1> 如果向一个NSArray请求一个Key,KVC会查找数组中每一个对象来查找Key,然后将查询结果打包到一个数组中并返回。
例如:Student里面有很多book对象
@interface Book : NSObject
@property (nonatomic,copy) NSString *name;
@property (nonatomic,assign) CGFloat price;
@end
@interface Student : NSObject
@property (nonatomic,strong) NSArray *books;
@end
要获取Student中所有Book的name ,语法形式如下:
NSArray *names = [student.books valueForKeyPath:@"name"];
或者
NSArray *names = [student valuesForKeyPath:@"books.name"];
注意:不能在键路径中为数组添加索引,比如:@"book[0].name".
1.4. 键路径运算符
1> 在键路径中,可以引用一些运算符来竞选一些运算,例如获取一些值平均数、最小数、最大数、总数等。以下举例:
1) 计算Student中Book对象的总数
NSNumber *count = [student.books valueForKeyPath:@"@count"];
或者
NSNumber *count = [student valueForKeyPath:@"books.@count"];
2) 计算Student中所有Book的价钱(price)总和
NSNumber *sum = [student.books valueForKeyPath:@"@sum.price"];
或者
NSNumber *sum = [student valueForKeyPath:@"books.@sum.price"];
3) 找出Student中Book的所有不同价位(排除相同价位)
NSArray *prices = [student.books valueForKeyPath:@"@distinctUnionOfObjects.price"];
或者
NSArray *prices = [student valueForKeyPath:@"books.@distinctUnionOfObjects.price"];
2. KVO(key value observing)
1> KVO是一种非常重要的机制,它允许监听对象的属性的变化
2> 注册监听器方法,如有形式如下:
-(void)addObserver:(NSObject*)anObjecter //监听器对象
forKeyPath:(NSString *) keyPath //监听的属性
options:(NSKeyValueObservingOptions)options //决定当前属性变化时,要传什么数据给监听器
context:(void *)context;
3> 监听器需要实现监听方法,语法形式如下:
-(void)observeValueForKeyPath:(NSString *)keyPath //监听的属性
ofObject:(id)object //谁的属性改变了
change:(NSDictionary*)change //属性改变时传过来的信息,(取决于添加监听器时option参数)
context:(void*)context;
4> 移除监听器,其语法形式如下:
-(void)removeObserver:(NSObject*)observer forKeyPath:(NSString*)keyPath;
【示例 - KVC && KVO】
/** Card 身份证 **/ #import <Foundation/Foundation.h> @interface Card : NSObject @property (strong,nonatomic) NSString *cardNo; @end #import "Card.h" @implementation Card - (NSString *)description { return [NSString stringWithFormat:@"<Card:%p cardNo=%@>", self,self.cardNo]; } @end
/** Book 书本 **/
#import <Foundation/Foundation.h> @interface Book : NSObject //书名 @property (nonatomic,strong) NSString *bookName; //价格 @property (nonatomic,assign) CGFloat price; @end #import "Book.h" @implementation Book - (NSString *)description { return [NSString stringWithFormat:@"<Book:%p bookName=%@ price=%f>", self,self.bookName,self.price]; } @end
/** Person 人 **/ #import <Foundation/Foundation.h> #import "Card.h" @interface Person : NSObject //姓名 @property (nonatomic,strong) NSString *name; //年龄 @property (nonatomic,assign) NSInteger age; //身份证 @property (nonatomic,strong) Card *card; //书本 @property (nonatomic,strong) NSArray *books; @end #import "Person.h" @implementation Person - (NSString *)description { return [NSString stringWithFormat:@"<Person:%p name=%@ age=%d card=%@ books=%@>", self,self.name,self.age,self.card,self.books]; } @end
/** 控制器类 **/ #import <UIKit/UIKit.h> @interface MainViewController : UIViewController @end #import "MainViewController.h" #import "Person.h" #import "Book.h" @implementation MainViewController -(void)viewDidLoad{ [super viewDidLoad]; UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect]; [button setTitle:@"测试" forState:UIControlStateNormal]; [button setFrame:CGRectMake(60, 100, 200, 50)]; [button addTarget:self action:@selector(testMethod1) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:button]; UIButton *button2 = [UIButton buttonWithType:UIButtonTypeRoundedRect]; [button2 setTitle:@"Plist测试" forState:UIControlStateNormal]; [button2 setFrame:CGRectMake(60, 150, 200, 100)]; [button2 addTarget:self action:@selector(testMethod2) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:button2]; UIButton *button3 = [UIButton buttonWithType:UIButtonTypeRoundedRect]; [button3 setTitle:@"KVO测试" forState:UIControlStateNormal]; [button3 setFrame:CGRectMake(60, 200, 200, 100)]; [button3 addTarget:self action:@selector(kvoTest) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:button3]; } -(void) testMethod1{ Person *person = [[Person alloc]init]; //设置Person自身属性 [person setValue:@"yyy" forKeyPath:@"name"]; [person setValue:@20 forKeyPath:@"age"]; //设置Person.Card属性 person.card = [[Card alloc]init]; [person setValue:@"342225" forKeyPath:@"card.cardNo"]; Book *book1 = [[Book alloc]init]; book1.bookName = @"IOS 1"; book1.price = 28.98; Book *book2 = [[Book alloc]init]; book2.bookName = @"IOS 2"; book2.price = 38.98; person.books = @[book1,book2]; NSLog(@"%@",person); NSLog(@"booksName = %@",[person valueForKeyPath:@"books.bookName"]); } -(void) testMethod2{ NSString *path = [[NSBundle mainBundle]pathForResource:@"persons" ofType:@"plist"]; NSArray *array = [NSArray arrayWithContentsOfFile:path]; NSMutableArray *persons = [NSMutableArray arrayWithCapacity:array.count]; for (NSDictionary *dic in array) { Person *p = [[Person alloc]init]; [p setValuesForKeysWithDictionary:dic]; [persons addObject:p]; } NSLog(@"persons = %@",persons); } -(void) kvoTest{ Person *p = [[Person alloc]init]; p.card = [[Card alloc]init]; p.name = @"wyp"; [p addObserver:self forKeyPath:@"card.cardNo" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil]; p.card.cardNo = @"123"; p.age = 20; [p removeObserver:self forKeyPath:@"card.cardNo"]; p.card.cardNo = @"qqqqq"; } -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{ NSLog(@"%@ %@ %@ %@",keyPath,object,change,context); } @end
/** plist文件 **/ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <array> <dict> <key>name</key> <string>wyp</string> <key>age</key> <integer>26</integer> <key>card</key> <dict> <key>cardNo</key> <string>34222519881229445X</string> </dict> <key>books</key> <array> <dict> <key>bookName</key> <string>IOS 1</string> <key>price</key> <real>28.98</real> </dict> <dict> <key>bookName</key> <string>IOS 2</string> <key>price</key> <real>38.98</real> </dict> </array> </dict> <dict> <key>name</key> <string>qlp</string> <key>age</key> <integer>26</integer> <key>card</key> <dict> <key>cardNo</key> <string>34222519891006374X</string> </dict> <key>books</key> <array> <dict> <key>bookName</key> <string>PS 1</string> <key>price</key> <real>28.98</real> </dict> <dict> <key>bookName</key> <string>PS 2</string> <key>price</key> <real>38.98</real> </dict> </array> </dict> </array> </plist>

浙公网安备 33010602011771号