KVC和KVO操作
来源:互联网 发布:idea 测试java代码 编辑:程序博客网 时间:2024/06/05 07:28
KVC是KeyValueCoding的简称,它是一种可以直接通过字符串的名字(key)来访问类属性(实例变量)的机制。而不是通过调用Setter、Getter方法访问。(和Java中是使用反射机制去访问类的private权限的变量类似,很暴力的.这样做就会破坏类的封装性!)当使用KVO、Core Data、CocoaBindings、AppleScript(Mac支持)时,KVC是关键技术。
关键方法定义在:NSKeyValueCodingprotocol
KVC支持类对象和内建基本数据类型。
获取值
valueForKey:,传入NSString属性的名字。
valueForKeyPath:,传入NSString属性的路径,xx.xx形式。
valueForUndefinedKey它的默认实现是抛出异常,可以重写这个函数做错误处理。
修改值
setValue:forKey:
setValue:forKeyPath:
setValue:forUndefinedKey:
setNilValueForKey:当对非类对象属性设置nil时,调用,默认抛出异常。
一对多关系成员的情况
mutableArrayValueForKey:有序一对多关系成员 NSArray
mutableSetValueForKey:无序一对多关系成员 NSSet
实例
Person.h
#import <Foundation/Foundation.h>#import "Dog.h"@interface Person : NSObject{ @private NSString *_name; NSInteger _age; Dog *_dog;}- (void)setName:(NSString *)name;@end
Person.m
#import "Person.h"@implementation Person- (void)setName:(NSString *)name{ _name = name; NSLog(@"KVC在赋值是会优先调用setter方法");}- (NSString *)description{ return [NSString stringWithFormat:@"name = %@,dog = %@, age = %ld, dog.weight = %.2f", _name, _dog, _age, _dog.weight];}@end
Dog.h
#import <Foundation/Foundation.h>@interface Dog : NSObject@property (nonatomic, assign) double weight;@end
Dog.m
#import "Dog.h"@implementation Dog@end
Main.m
#import <Foundation/Foundation.h>#import "Person.h"#import "Dog.h"/** KVC:即使一个类的属性是私有的,而且也没有setter/getter方法,同样可以读写. 很暴力 相当于JAVA中的反射,破坏类的封装性 */int main(int argc, const char * argv[]) { @autoreleasepool { Person *p = [[Person alloc] init]; Dog *d = [[Dog alloc] init]; //设置值 //KVC设置值时,如果属性中有setter方法,则优先调用setter方法,如果没有则直接设置上去,getter方法类似 [p setValue:@"ly" forKey:@"name"]; //如果在设置Value时,没有对应的key,程序就会崩溃 [p setValue:d forKeyPath:@"dog"]; //[p setValue:@"0.5" forKey:@"dog.weight"];(错误) [p setValue:@"0.5" forKeyPath:@"dog.weight"]; //设置基本数据类型 //这里需要将基本类型转化成NSNumber,在设置值的时候,会有自动解包,NSNumber会解包赋值给age [p setValue:@23 forKeyPath:@"_age"]; NSDictionary *personDict = @{@"name" : @"sunny", @"age" : @"22", @"dog" : [[Dog alloc] init]}; Person *person = [[Person alloc] init]; // 字典转模型:setValuesForKeysWithDictionary // 1>必须字典中对应的key和模型中对应的属性是一致 // 2>字典中存在的属性,在模型中必须有对应的属性 [person setValuesForKeysWithDictionary:personDict]; NSLog(@"person:%@", person); //读取值 NSString *name = [p valueForKey:@"_name"]; NSLog(@"%@",name); NSLog(@"%@",p); } return 0;}
下面再来看一下KVC中强大的功能:键值路径
键值路径是对于一个类中有数组对象的属性进行便捷操作。
Author.h
#import <Foundation/Foundation.h>@interface Author : NSObject{ NSString *_name; //一个作者对应多个出版书籍 NSArray *_issueBook;}@end
Author.m
#import "Author.h"@implementation Author@end
Book.h
#import <Foundation/Foundation.h>#import "Author.h"@interface Book : NSObject{ Author *_author;}@property NSString *name;@property float price;@end
Book.m
#import "Book.h"@implementation Book@end
Main.m
#import <Foundation/Foundation.h>#import "Author.h"#import "Book.h"/** 键值路径是对于一个类中有数组对象的属性进行便捷操作; */int main(int argc, const char * argv[]) { @autoreleasepool { Author *author = [[Author alloc] init]; [author setValue:@"ly" forKey:@"name"]; Book *book1 = [[Book alloc] init]; book1.name = @"iOS开发进阶"; book1.price = 98.00f; Book *book2 = [[Book alloc] init]; book2.name = @"Android内核解析"; book2.price =88.00f; NSArray *books = [NSArray arrayWithObjects:book1, book2, nil]; [author setValue:books forKey:@"issueBook"]; //基本数据类型会自动装箱成NSNumber,装到数组中; //得到所有书籍的价格 NSArray *prices = [author valueForKeyPath:@"issueBook.price"]; NSLog(@"prices = %@", prices); //获取数组的大小 NSNumber *count = [author valueForKeyPath:@"issueBook.@count"]; NSLog(@"count = %@", count); //获取书籍价格的总和 NSNumber *priceSum = [author valueForKeyPath:@"issueBook.@sum.price"]; NSLog(@"priceSum = %@", priceSum); //获取书籍价格的平均值 NSNumber *priceAvg = [author valueForKeyPath:@"issueBook.@avg.price"]; NSLog(@"priceAvg = %@", priceAvg); //获取书籍价格的最大值和最小值 NSNumber *max = [author valueForKeyPath:@"issueBook.@max.price"]; NSNumber *min = [author valueForKeyPath:@"issueBook.@min.price"]; NSLog(@"max = %@, min = %@", max, min); } return 0;}
一,KVO概述
KVO,即:Key-Value Observing,它提供一种机制,当指定的对象的属性被修改后,则对象就会接受到通知。简单的说就是每次指定的被观察的对象的属性被修改后,KVO就会自动通知相应的观察者了。
二,使用方法
系统框架已经支持KVO,所以程序员在使用的时候非常简单。
1. 注册,指定被观察者的属性,
2. 实现回调方法
3. 移除观察
三,实例:
现在有一个小孩类,他有两个属性:开心值,饥饿值,然后还有一个护士类,用来监听孩子类的这两个属性值的
Children.h
#import <Foundation/Foundation.h>/** 定义一个小孩类,它由两个属性,开心值和饥饿值 */@interface Children : NSObject@property (nonatomic, assign) NSInteger happyValue;@property (nonatomic, assign) NSInteger hurryValue;@end
Children.m
#import "Children.h"@implementation Children- (instancetype)init{ self = [super init]; if (self) { //启动定时器 每隔一秒去修改孩子类的值 [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerAction:) userInfo:nil repeats:YES]; self.happyValue = 100; } return self;}- (void)timerAction:(NSTimer *)timer{ //使用setter方法修改属性值才能触发KVO self.hurryValue = --_hurryValue; self.happyValue = --_happyValue; }@end
Nure.h
#import <Foundation/Foundation.h>@class Children;@interface Nure : NSObject@property (nonatomic, strong) Children *children;- (instancetype)initWithChildren:(Children *)children;@end
Nure.m
#import "Nure.h"#import "Children.h"@implementation Nure- (instancetype)initWithChildren:(Children *)children{ if (self = [super init]) { _children = children; //观察孩子的happyValue //使用KVO为_children对象添加一个观察者,用于观察监听happyValue属性值是否被修改 [_children addObserver:self forKeyPath:@"happyValue" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:@"context"]; //观察孩子的hurryValue [_children addObserver:self forKeyPath:@"hurryValue" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:@"context"]; } return self;}//触发方法- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context{ //通过打印输出change,可以看到对应的key NSLog(@"%@",change); //通过keyPath来判断不同属性的观察者 if ([keyPath isEqualToString:@"happyValue"]) { //这里change中有old和new的值是因为在调用addObserver方法时,用到了 //options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld NSNumber *happyValue = [change objectForKey:@"new"];//修改之后的最新值 NSInteger value = [happyValue integerValue]; if (value < 80) { NSLog(@"孩子的开心值小于90"); } }else if ([keyPath isEqualToString:@"hurryValue"]) { NSNumber *hurryValue = [change objectForKey:@"new"];//修改之后的最新值 NSInteger value = [hurryValue integerValue]; if (value < 0) { NSLog(@"孩子的饥饿值小于0"); } } //打印addObserver方法的context参数 NSLog(@"%@", context); //使用KVO去修改属性的值,也会触发事件 }- (void)dealloc{ //移除观察者(这个并不属于KVO的内容) [_children removeObserver:self forKeyPath:@"happyValue"]; [_children removeObserver:self forKeyPath:@"hurryValue"];}@end
Main.m
#import <Foundation/Foundation.h>#import "Children.h"#import "Nure.h"/** KVO 这种机制在JAVA中是不存在的 它的作用就是用来监听类中属性值的变化,实现原理是观察者模式,当然我们也可以使用观察者模式在java中实现这样的机制 */int main(int argc, const char * argv[]) { @autoreleasepool { Children *children = [[Children alloc] init]; Nure *nure = [[Nure alloc] initWithChildren:children]; //启动 [[NSRunLoop currentRunLoop] run]; } return 0;}
小结:
KVO/KVC这种编码方式使用起来很简单,很适用与datamodel修改后,引发的UIVIew的变化这种情况,就像上边的例子那样,当更改属性的值后,监听对象会立即得到通知。
- KVC和KVO操作
- kvo 和kvc
- KVO和KVC
- KVC和KVO简介
- kvo和kvc
- Iphone 和 KVC/KVO
- kvc和kvo
- KVC和KVO
- KVC、KVO和谓词
- KVC和KVO
- KVO和KVC
- KVC 和KVO机制
- KVO和KVC
- KVC 和 KVO
- KVC和KVO
- ios kvc和kvo
- KVC和KVO
- KVC、KVO和谓词
- s:select 默认值问题
- 黑马程序员--反射
- ORA-01033: ORACLE initialization or shutdown in progress数据文件损坏错误解决方案
- Maven实践(二):Spring与classpath*加载配置文件
- wampserver出现You don’t have permission to access/on this
- KVC和KVO操作
- ActionBar的使用方式+Selector
- 一看就懂的iOS触摸事件
- C语言基础—字符串输入输出函数puts和gets
- 1.Activity的建立,配置和使用
- 虚函数实现原理(转)
- Eclipse快捷键 10个最有用的快捷键
- android中Fragment的构造函数
- 数值优化(Numerical Optimization)学习系列-带约束最优化(Constrained Optimization)