【OC语言连载十】KVC、KVO、谓词

内容提纲:
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 ;
}








  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值