内容提纲:
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 ;
- ( 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" ];
@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 ;
}
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 *)#>
// // 调用此方法的话,会打印出此方法名
// 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 );
// 复写初始化方法
- ( 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 ];
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;
@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
@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" );
}
/* 注意:
只有通过 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;
#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" );
}
@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 {
#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 ;
jack. life = 100 ;
jack. mofa = 200 ;
Nurse *nurse = [[Nurse alloc]init];
nurse.
child
= jack;
[jack
fight
];
[jack rest ];
}
return 0 ;
[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 ;
}