【OC语言连载十】KVC、KVO、谓词
2015-08-12 08:35
495 查看
内容提纲:
1、KVC 键值编码(KeyValue Coding)
2、KVO 基于键值的观察者(KeyValue Observing)
3、谓词
一、KVC 键值编码(KeyValue Coding)
1、【KVC简介】
(1) 一种可通过字符串的名字(key)来访问类属性的机制。
(2)该机制无需调用存取方法和变量实例就可访问对象属性。
(3)//破坏了类的封装性
2、【KVC基本用法】(与字典中区分开)
//设值
[ps
setValue:@"Jack"
forKey:@"name"];
//取值
NSString
*name = [ps
valueForKey:@"name"];
3、【KVC执行步骤与使用经验】
/*
//KVC步骤
//1、首先先找后面的key有没有这个get(setter)方法,如果有,则直接调用
//2、如果没有get(setter)方法,直接找_key这个属性,如果说没有找到_key,然后再去找(key)这个属性,然后直接赋值
//3、如果key这个属性也没有,则报错,重写
//经验:
使用KVC时,设置的key最好不要加_,因为系统会自动地去优先地寻找_key这个属性
*/
4、【KVC异常捕获】
在.m文件中重写以下两个方法:
//此方法用来捕获程序设置方法的异常
- (void)setValue:(id)value
forUndefinedKey:(NSString
*)key{
NSLog(@"%@------%@
不存在键值对路径",key, value);
}
//此方法用来捕获程序访问方法的异常
- (id)valueForUndefinedKey:(NSString
*)key{
NSLog(@"%@属性值不存在",key);
return
nil;
}
5、【KVC 路径与一对多的关系】
int
main(int
argc,
const
char * argv[]) {
@autoreleasepool {
//键值路径--数组作值,实现简单计算
//创建书对象
Book *book1 = [[Book
alloc]
init];
[book1
setValue:@"西游记"
forKeyPath:@"name"];
[book1
setValue:@12
forKeyPath:@"price"];
Book *book2 = [[Book
alloc]
init];
[book2
setValue:@"红楼梦"
forKeyPath:@"name"];
[book2
setValue:@13
forKeyPath:@"price"];
//将书对象放入数组books中:
NSArray *books =
@[book1, book2];
[book1
release];
[book2
release];
//创建人对象
Person *jack = [[Person
alloc]init];
//给人的books属性设值(books数组)
[jack
setValue:books
forKey:@"books"];
//将数组中的元素的price属性值放入一个新数组中
NSArray *prices = [jack
valueForKeyPath:@"books.price"];
NSLog(@"prices is %@", prices);
NSArray *booknames = [jack
valueForKeyPath:@"books.name"];
NSLog(@"booknames is %@", booknames);
//进行简单计算
NSString *count = [jack
valueForKeyPath:@"books.@count"];
NSLog(@"count : %@", count);
NSString *sum = [jack
valueForKeyPath:@"books.@sum.price"];
NSLog(@"sum : %@", sum);
NSString *avg = [jack
valueForKeyPath:@"books.@avg.price"];
NSLog(@"avg : %@", avg);
NSString *min = [jack
valueForKeyPath:@"books.@min.price"];
NSLog(@"min : %@", min);
NSString *max = [jack
valueForKeyPath:@"books.@max.price"];
NSLog(@"max : %@", max);
[jack
release];
}
return
0;
}
二、KVO 基于键值的观察者(KeyValue Observing)
提供一种机制,当指定对象的属性被修改后,则对相会收到通知。
注意KVO与NSNotification的区别
1、【NSNotification】
Child.m文件中:
@implementation
Child
- (void)kouKe{
// //调用此方法的话,会打印出此方法名
// NSLog(@"%s",__FUNCTION__);//会打印:“-[Child
kouKe]”
NSLog(@"口渴了");
//发送全局通知,通过通知中心发送
//拿到全局通知对象
NSNotificationCenter *notificationCenter = [NSNotificationCenter
defaultCenter];
//发送一条通知
// [notificationCenter postNotificationName:@"Child_kouke" object:nil];
//另一种发送一条通知的方法
//userInfo:<#(NSDictionary *)#>
@end
Nurse.m文件中(Nurse有name属性(.h文件中)和倒水方法)
@implementation
Nurse
//复写初始化方法
- (instancetype)init{
self = [super
init];
if (self) {
//..
//让当前对象作为小孩发送通知的接受者
//Observer:
通知的接收者,谁来接受这个通知,一般都是self
//selector:
当通知发起起,接收者做出什么样的改变,接收者执行的方法名
//name:
通知名称
[[NSNotificationCenter
defaultCenter]
addObserver:self
selector:@selector(daoShui:)
name:@"Child_kouke"
object:nil];
}
return
self;
}
//倒水方法
- (void)daoShui:(NSNotification
*)notification{
//打印出通知的信息:
NSLog(@"name:%@, object:%@, userInfo%@",notification.name,
notification.object, notification.userInfo);
NSLog(@"Nurse %@
给你倒水",_name);
}
- (void)dealloc{
NSLog(@"Nurse dead");
//移除通知
[[NSNotificationCenter
defaultCenter]
removeObserver:self];
}
@end
2、【KVO的使用】
//*********** KVO的使用(以小孩、护士为例)
*************
/**小孩有属性:(生命值、魔法值),方法:(打架、休息)
**护士有属性:(小孩)
**护士监听小孩状态,显示小孩的最新状态
*******************/
Child.h文件中:
#import
<Foundation/Foundation.h>
@interface
Child :
NSObject
{
NSInteger _life;
NSInteger _mofa;
}
@property
(nonatomic,
assign)
NSInteger
life;
@property
(nonatomic,
assign)
NSInteger
mofa;
- (void)fight;
- (void)rest;
@end
Child.m文件中:
#import
"Child.h"
@implementation
Child
- (void)fight{
/*注意:
只有通过KVC
或
setter
方法,修改了life值,才能够调用通知方法
如果使用直接修改,将无法调用变更的通知方法
//不能用_life -= 50;
*/
self.life
-=
50;
// [self setValue:@50 forKey:@"life"];
}
- (void)rest{
self.mofa
+=
20;
}
- (void)dealloc{
NSLog(@"Child dead");
}
@end
Nurse.h文件中:
#import
<Foundation/Foundation.h>
#import
"Child.h"
@interface
Nurse :
NSObject
{
Child *_child;
}
@property
(nonatomic,
retain)
Child
*child;
@end
Nurse.m文件中:
#import
"Nurse.h"
@implementation
Nurse
- (void)setChild:(Child
*)child{
_child = child;
//...
//第一步
//注册观察者,给孩子添加一个照顾的人
//Observer:
观察对象
//KeyPath:
被观察对象的属性值
//options:
观察的旧值或者新值
//context:
上下文,传递一个参数,一般设为nil
[_child
addObserver:self
forKeyPath:@"life"
options:NSKeyValueObservingOptionNew
|
NSKeyValueObservingOptionOld
context:nil];
[_child
addObserver:self
forKeyPath:@"mofa"
options:NSKeyValueObservingOptionNew
|
NSKeyValueObservingOptionOld
context:nil];
}
//第二步
//接收变更通知
//KeyPath:
所观察的键值路径
//Object:
被观察的对象
//change:
信息值,包含了新值和旧值
//context:
传过来的参数,一般为nil
- (void)observeValueForKeyPath:(NSString
*)keyPath ofObject:(id)object change:(NSDictionary
*)change context:(void
*)context{
// NSLog(@"keyPath is %@",keyPath);
// NSLog(@"object is %@",object);
// NSLog(@"change is %@",change);
// NSLog(@"context is %@",context);
if ([keyPath
isEqualToString:@"life"]) {
NSNumber *newNum = [change
objectForKey:@"new"];
NSLog(@"最新的生命值是:%@",newNum);
}
if ([keyPath
isEqualToString:@"mofa"]) {
NSNumber *newNum = [change
objectForKey:@"new"];
NSLog(@"最新的魔法值是:%@",newNum);
}
}
- (void)dealloc{
//第三步
//移除观察者
[_child
removeObserver:self
forKeyPath:@"life"
context:nil];
[_child
removeObserver:self
forKeyPath:@"mofa"
context:nil];
NSLog(@"Nurse dead");
}
@end
main.m文件中:
#import
<Foundation/Foundation.h>
#import
"Child.h"
#import
"Nurse.h"
int
main(int
argc,
const
char * argv[]) {
@autoreleasepool {
//*********** KVO的使用
*************
Child *jack = [[Child
alloc]init];
jack.life
=
100;
jack.mofa
=
200;
Nurse *nurse = [[Nurse
alloc]init];
nurse.child
= jack;
[jack
fight];
[jack
rest];
}
return
0;
}
三、谓词
#import
<Foundation/Foundation.h>
#import
"Person.h"
//Person类有属性(姓名,年龄)
int
main(int
argc,
const
char * argv[]) {
@autoreleasepool {
Person *ps1 = [[Person
alloc]init];
[ps1
setValue:@"jack"
forKey:@"name"];
[ps1
setValue:@13
forKey:@"age"];
Person *ps2 = [[Person
alloc]init];
[ps2
setValue:@"jim"
forKey:@"name"];
[ps2
setValue:@17
forKey:@"age"];
Person *ps3 = [[Person
alloc]init];
[ps3
setValue:@"rose"
forKey:@"name"];
[ps3
setValue:@10
forKey:@"age"];
Person *ps4 = [[Person
alloc]init];
[ps4
setValue:@"neccy"
forKey:@"name"];
[ps4
setValue:@16
forKey:@"age"];
NSArray *arry =
@[ps1, ps2, ps3, ps4];
//创建谓词
//设置谓词条件
NSPredicate *pre1 =[NSPredicate
predicateWithFormat:@"age <= 17"];
for (Person
*person
in arry) {
//表示指定对象是否满足谓词条件
if ([pre1
evaluateWithObject:person]) {
NSLog(@"person name is %@", person.name);
}
}
//返回一个符合谓词条件的数组
NSArray *arr1 = [arry
filteredArrayUsingPredicate:pre1];
for (Person
*person
in arr1) {
NSLog(@"person name is %@", [person
valueForKey:@"name"]);
}
NSLog(@"arr1 is %@", arr1);
//格式占位符
NSPredicate *pre2 =[NSPredicate
predicateWithFormat:@"age <= %d",
10];
NSArray *arr2 = [arry
filteredArrayUsingPredicate:pre2];
for (Person
*person
in arr2) {
NSLog(@"person name is %@", [person
valueForKey:@"name"]);
}
/********************运算符********************/
//逻辑运算符
NSPredicate *pre3 = [NSPredicate
predicateWithFormat:@"name > 'opp' && age < %d",
16];
NSArray *arr3 = [arry
filteredArrayUsingPredicate:pre3];
NSLog(@"person name is %@", [arr3
valueForKey:@"name"]);
//关键字IN
NSPredicate *pre4 = [NSPredicate
predicateWithFormat:@"name IN {'rose', 'back', 'jim', 'tom'}"];
NSArray *arr4 = [arry
filteredArrayUsingPredicate:pre4];
NSLog(@"person name is %@", [arr4
valueForKey:@"name"]);
//以。。。开始------BEGINSWITH
NSPredicate *pre5 = [NSPredicate
predicateWithFormat:@"self.name
BEGINSWITH 'j' "];
NSArray *arr5 = [arry
filteredArrayUsingPredicate:pre5];
NSLog(@"person name is %@", [arr5
valueForKey:@"name"]);
//以。。。。结束----ENDSWITH
NSPredicate *pre6 = [NSPredicate
predicateWithFormat:@"self.name
ENDSWITH 'm' "];
NSArray *arr6 = [arry
filteredArrayUsingPredicate:pre6];
NSLog(@"person name is %@", [arr6
valueForKey:@"name"]);
//包含---CONTAINS
NSPredicate *pre7 = [NSPredicate
predicateWithFormat:@"self.name
CONTAINS 'e' "];
NSArray *arr7 = [arry
filteredArrayUsingPredicate:pre7];
NSLog(@"person name is %@", [arr7
valueForKey:@"name"]);
}
return
0;
}
1、KVC 键值编码(KeyValue Coding)
2、KVO 基于键值的观察者(KeyValue Observing)
3、谓词
一、KVC 键值编码(KeyValue Coding)
1、【KVC简介】
(1) 一种可通过字符串的名字(key)来访问类属性的机制。
(2)该机制无需调用存取方法和变量实例就可访问对象属性。
(3)//破坏了类的封装性
2、【KVC基本用法】(与字典中区分开)
//设值
[ps
setValue:@"Jack"
forKey:@"name"];
//取值
NSString
*name = [ps
valueForKey:@"name"];
3、【KVC执行步骤与使用经验】
/*
//KVC步骤
//1、首先先找后面的key有没有这个get(setter)方法,如果有,则直接调用
//2、如果没有get(setter)方法,直接找_key这个属性,如果说没有找到_key,然后再去找(key)这个属性,然后直接赋值
//3、如果key这个属性也没有,则报错,重写
//经验:
使用KVC时,设置的key最好不要加_,因为系统会自动地去优先地寻找_key这个属性
*/
4、【KVC异常捕获】
在.m文件中重写以下两个方法:
//此方法用来捕获程序设置方法的异常
- (void)setValue:(id)value
forUndefinedKey:(NSString
*)key{
NSLog(@"%@------%@
不存在键值对路径",key, value);
}
//此方法用来捕获程序访问方法的异常
- (id)valueForUndefinedKey:(NSString
*)key{
NSLog(@"%@属性值不存在",key);
return
nil;
}
5、【KVC 路径与一对多的关系】
int
main(int
argc,
const
char * argv[]) {
@autoreleasepool {
//键值路径--数组作值,实现简单计算
//创建书对象
Book *book1 = [[Book
alloc]
init];
[book1
setValue:@"西游记"
forKeyPath:@"name"];
[book1
setValue:@12
forKeyPath:@"price"];
Book *book2 = [[Book
alloc]
init];
[book2
setValue:@"红楼梦"
forKeyPath:@"name"];
[book2
setValue:@13
forKeyPath:@"price"];
//将书对象放入数组books中:
NSArray *books =
@[book1, book2];
[book1
release];
[book2
release];
//创建人对象
Person *jack = [[Person
alloc]init];
//给人的books属性设值(books数组)
[jack
setValue:books
forKey:@"books"];
//将数组中的元素的price属性值放入一个新数组中
NSArray *prices = [jack
valueForKeyPath:@"books.price"];
NSLog(@"prices is %@", prices);
NSArray *booknames = [jack
valueForKeyPath:@"books.name"];
NSLog(@"booknames is %@", booknames);
//进行简单计算
NSString *count = [jack
valueForKeyPath:@"books.@count"];
NSLog(@"count : %@", count);
NSString *sum = [jack
valueForKeyPath:@"books.@sum.price"];
NSLog(@"sum : %@", sum);
NSString *avg = [jack
valueForKeyPath:@"books.@avg.price"];
NSLog(@"avg : %@", avg);
NSString *min = [jack
valueForKeyPath:@"books.@min.price"];
NSLog(@"min : %@", min);
NSString *max = [jack
valueForKeyPath:@"books.@max.price"];
NSLog(@"max : %@", max);
[jack
release];
}
return
0;
}
二、KVO 基于键值的观察者(KeyValue Observing)
提供一种机制,当指定对象的属性被修改后,则对相会收到通知。
注意KVO与NSNotification的区别
1、【NSNotification】
Child.m文件中:
@implementation
Child
- (void)kouKe{
// //调用此方法的话,会打印出此方法名
// NSLog(@"%s",__FUNCTION__);//会打印:“-[Child
kouKe]”
NSLog(@"口渴了");
//发送全局通知,通过通知中心发送
//拿到全局通知对象
NSNotificationCenter *notificationCenter = [NSNotificationCenter
defaultCenter];
//发送一条通知
// [notificationCenter postNotificationName:@"Child_kouke" object:nil];
//另一种发送一条通知的方法
//userInfo:<#(NSDictionary *)#>
@end
Nurse.m文件中(Nurse有name属性(.h文件中)和倒水方法)
@implementation
Nurse
//复写初始化方法
- (instancetype)init{
self = [super
init];
if (self) {
//..
//让当前对象作为小孩发送通知的接受者
//Observer:
通知的接收者,谁来接受这个通知,一般都是self
//selector:
当通知发起起,接收者做出什么样的改变,接收者执行的方法名
//name:
通知名称
[[NSNotificationCenter
defaultCenter]
addObserver:self
selector:@selector(daoShui:)
name:@"Child_kouke"
object:nil];
}
return
self;
}
//倒水方法
- (void)daoShui:(NSNotification
*)notification{
//打印出通知的信息:
NSLog(@"name:%@, object:%@, userInfo%@",notification.name,
notification.object, notification.userInfo);
NSLog(@"Nurse %@
给你倒水",_name);
}
- (void)dealloc{
NSLog(@"Nurse dead");
//移除通知
[[NSNotificationCenter
defaultCenter]
removeObserver:self];
}
@end
2、【KVO的使用】
//*********** KVO的使用(以小孩、护士为例)
*************
/**小孩有属性:(生命值、魔法值),方法:(打架、休息)
**护士有属性:(小孩)
**护士监听小孩状态,显示小孩的最新状态
*******************/
Child.h文件中:
#import
<Foundation/Foundation.h>
@interface
Child :
NSObject
{
NSInteger _life;
NSInteger _mofa;
}
@property
(nonatomic,
assign)
NSInteger
life;
@property
(nonatomic,
assign)
NSInteger
mofa;
- (void)fight;
- (void)rest;
@end
Child.m文件中:
#import
"Child.h"
@implementation
Child
- (void)fight{
/*注意:
只有通过KVC
或
setter
方法,修改了life值,才能够调用通知方法
如果使用直接修改,将无法调用变更的通知方法
//不能用_life -= 50;
*/
self.life
-=
50;
// [self setValue:@50 forKey:@"life"];
}
- (void)rest{
self.mofa
+=
20;
}
- (void)dealloc{
NSLog(@"Child dead");
}
@end
Nurse.h文件中:
#import
<Foundation/Foundation.h>
#import
"Child.h"
@interface
Nurse :
NSObject
{
Child *_child;
}
@property
(nonatomic,
retain)
Child
*child;
@end
Nurse.m文件中:
#import
"Nurse.h"
@implementation
Nurse
- (void)setChild:(Child
*)child{
_child = child;
//...
//第一步
//注册观察者,给孩子添加一个照顾的人
//Observer:
观察对象
//KeyPath:
被观察对象的属性值
//options:
观察的旧值或者新值
//context:
上下文,传递一个参数,一般设为nil
[_child
addObserver:self
forKeyPath:@"life"
options:NSKeyValueObservingOptionNew
|
NSKeyValueObservingOptionOld
context:nil];
[_child
addObserver:self
forKeyPath:@"mofa"
options:NSKeyValueObservingOptionNew
|
NSKeyValueObservingOptionOld
context:nil];
}
//第二步
//接收变更通知
//KeyPath:
所观察的键值路径
//Object:
被观察的对象
//change:
信息值,包含了新值和旧值
//context:
传过来的参数,一般为nil
- (void)observeValueForKeyPath:(NSString
*)keyPath ofObject:(id)object change:(NSDictionary
*)change context:(void
*)context{
// NSLog(@"keyPath is %@",keyPath);
// NSLog(@"object is %@",object);
// NSLog(@"change is %@",change);
// NSLog(@"context is %@",context);
if ([keyPath
isEqualToString:@"life"]) {
NSNumber *newNum = [change
objectForKey:@"new"];
NSLog(@"最新的生命值是:%@",newNum);
}
if ([keyPath
isEqualToString:@"mofa"]) {
NSNumber *newNum = [change
objectForKey:@"new"];
NSLog(@"最新的魔法值是:%@",newNum);
}
}
- (void)dealloc{
//第三步
//移除观察者
[_child
removeObserver:self
forKeyPath:@"life"
context:nil];
[_child
removeObserver:self
forKeyPath:@"mofa"
context:nil];
NSLog(@"Nurse dead");
}
@end
main.m文件中:
#import
<Foundation/Foundation.h>
#import
"Child.h"
#import
"Nurse.h"
int
main(int
argc,
const
char * argv[]) {
@autoreleasepool {
//*********** KVO的使用
*************
Child *jack = [[Child
alloc]init];
jack.life
=
100;
jack.mofa
=
200;
Nurse *nurse = [[Nurse
alloc]init];
nurse.child
= jack;
[jack
fight];
[jack
rest];
}
return
0;
}
三、谓词
#import
<Foundation/Foundation.h>
#import
"Person.h"
//Person类有属性(姓名,年龄)
int
main(int
argc,
const
char * argv[]) {
@autoreleasepool {
Person *ps1 = [[Person
alloc]init];
[ps1
setValue:@"jack"
forKey:@"name"];
[ps1
setValue:@13
forKey:@"age"];
Person *ps2 = [[Person
alloc]init];
[ps2
setValue:@"jim"
forKey:@"name"];
[ps2
setValue:@17
forKey:@"age"];
Person *ps3 = [[Person
alloc]init];
[ps3
setValue:@"rose"
forKey:@"name"];
[ps3
setValue:@10
forKey:@"age"];
Person *ps4 = [[Person
alloc]init];
[ps4
setValue:@"neccy"
forKey:@"name"];
[ps4
setValue:@16
forKey:@"age"];
NSArray *arry =
@[ps1, ps2, ps3, ps4];
//创建谓词
//设置谓词条件
NSPredicate *pre1 =[NSPredicate
predicateWithFormat:@"age <= 17"];
for (Person
*person
in arry) {
//表示指定对象是否满足谓词条件
if ([pre1
evaluateWithObject:person]) {
NSLog(@"person name is %@", person.name);
}
}
//返回一个符合谓词条件的数组
NSArray *arr1 = [arry
filteredArrayUsingPredicate:pre1];
for (Person
*person
in arr1) {
NSLog(@"person name is %@", [person
valueForKey:@"name"]);
}
NSLog(@"arr1 is %@", arr1);
//格式占位符
NSPredicate *pre2 =[NSPredicate
predicateWithFormat:@"age <= %d",
10];
NSArray *arr2 = [arry
filteredArrayUsingPredicate:pre2];
for (Person
*person
in arr2) {
NSLog(@"person name is %@", [person
valueForKey:@"name"]);
}
/********************运算符********************/
//逻辑运算符
NSPredicate *pre3 = [NSPredicate
predicateWithFormat:@"name > 'opp' && age < %d",
16];
NSArray *arr3 = [arry
filteredArrayUsingPredicate:pre3];
NSLog(@"person name is %@", [arr3
valueForKey:@"name"]);
//关键字IN
NSPredicate *pre4 = [NSPredicate
predicateWithFormat:@"name IN {'rose', 'back', 'jim', 'tom'}"];
NSArray *arr4 = [arry
filteredArrayUsingPredicate:pre4];
NSLog(@"person name is %@", [arr4
valueForKey:@"name"]);
//以。。。开始------BEGINSWITH
NSPredicate *pre5 = [NSPredicate
predicateWithFormat:@"self.name
BEGINSWITH 'j' "];
NSArray *arr5 = [arry
filteredArrayUsingPredicate:pre5];
NSLog(@"person name is %@", [arr5
valueForKey:@"name"]);
//以。。。。结束----ENDSWITH
NSPredicate *pre6 = [NSPredicate
predicateWithFormat:@"self.name
ENDSWITH 'm' "];
NSArray *arr6 = [arry
filteredArrayUsingPredicate:pre6];
NSLog(@"person name is %@", [arr6
valueForKey:@"name"]);
//包含---CONTAINS
NSPredicate *pre7 = [NSPredicate
predicateWithFormat:@"self.name
CONTAINS 'e' "];
NSArray *arr7 = [arry
filteredArrayUsingPredicate:pre7];
NSLog(@"person name is %@", [arr7
valueForKey:@"name"]);
}
return
0;
}