15、KVC、KVO和谓词

KVC的基本用法

键值编码的基本概念和用法

1.键-值编码是一个用于间接访问对象属性的机制,使用该机制不需要调用存取方 法和变量实例就可访问对象属性。
2.键-值编码方法在Objective-C非正式协议(类目)NSKeyValueCoding中被声 明,默认的实现方法由NSObject提供。
3.键-值编码支持带有对象值的属性,同时也支持纯数值类型和结构。非对象参数 和返回类型会被识别并自动封装/解封。

·设置和访问

键/值编码中的基本调用包括-valueForKey:和-setValue:forkey:这两个方 法,它们以字符串的形式向对象发送消息,字符串是我们关注属性的关键。

Book *book = [[Book alloc] init];
NSMutableString *name = [[NSMutableString alloc] initWithFormat:@"jack"];
[book setValue:name forKey:@"name"];
NSLog(@"jack name : %@", [book valueForKey:@"name"]);

是否存在setter、getter方法,如果不存在,它将在内部查找名为_key或key的
实例变量。通过KVC,可以获取不存在getter方法的对象值,无需通过对象指针
直接访问。

这里我们需要注意,当我们通过setValue:forKey:设置对象的值,或通过valueForKey来获取对象的值时,如若对象的实例变量为基本数据类型时 (char、int、float、BOOL),我们需要对数据进行封装。

·路径

除了通过键设置值外,键/值编码还支持指定路径,像文件系统一样。用“点”号 隔开。

[book setValue:@"比尔" forKeyPath:@"author._name"]; 
[book valueForKeyPath:@"realtiveBooks.price"]

·一对多的关系

如果向NSArray请求一个键值,它实际上会查询数组中的每个对象来查找这个键 值,然后将查询结果打包到另一个数组中并返回给你。

NSArray *booksArray = [NSArray arrayWithObjects:book1, book2, nil];
[book setValue:booksArray forKey:@"relativeBooks"];
NSLog(@"books 2: %@", [book valueForKeyPath:@"relativeBooks.price"]);

·KVC的简单运算

此外,还可以应用一些字符做简单运算。sum、min、max、avg、count

NSNumber *count = [book valueForKeyPath:@"relativeBooks.@count"];
NSLog(@"count : %@", count);
NSNumber *sum = [book valueForKeyPath:@"relativeBooks.@sum._price"];
NSLog(@"sum : %@", sum);
NSNumber *avg = [book valueForKeyPath:@"relativeBooks.@avg._price"];
NSLog(@"avg : %@", avg);
NSNumber *min = [book valueForKeyPath:@"relativeBooks.@min._price"];
NSLog(@"min : %@", min);
NSNumber *max = [book valueForKeyPath:@"relativeBooks.@max._price"];
NSLog(@"max : %@", max); 

例子

//Author.h
#import <Foundation/Foundation.h>

@interface Author : NSObject {
@private
    NSString *_name;
}
@end

//Author.m
#import "Author.h"

@implementation Author

@end

//Book.h
#import <Foundation/Foundation.h>
#import "Author.h"

@interface Book : NSObject {
@private
    NSString *_name;
    Author *_author;    //书的作者
    NSArray *_relativeBooks; //相关的书籍

    float price;        //书的价格
}

@end

//Book.m
#import "Book.h"

@implementation Book

@end

//main.h

#import <Foundation/Foundation.h>
#import "Book.h"

int main(int argc, const char * argv[])
{

    @autoreleasepool {
        Book *book = [[Book alloc] init];
        Author *author = [[Author alloc] init];
        [author setValue:@"jack" forKey:@"_name"];
        [book setValue:[NSNumber numberWithFloat:12.6] forKey:@"price"];

        NSNumber *price = [book valueForKeyPath:@"price"];
        NSLog(@"%@",price);

        //键值访问
        [book setValue:@"ipad develper" forKey:@"name"];
        [book setValue:author forKey:@"_author"];

        //路径访问
        [book setValue:@"tom" forKeyPath:@"author.name"];
        NSString *authorName = [book valueForKeyPath:@"_author._name"];
        NSLog(@"%@",authorName);

        //一对多的关系
        NSMutableArray *releBooks = [NSMutableArray arrayWithCapacity:3];
        for (int i=0; i<3; i++) {
            Book *book = [[Book alloc] init];
            NSString *name = [NSString stringWithFormat:@"job_%d",i];
            [book setValue:name forKey:@"_name"];

            [book setValue:@(12+i) forKey:@"price"];
            [releBooks addObject:book];
            [book release];
        }
        [book setValue:releBooks forKey:@"_relativeBooks"];

        NSArray *names = [book valueForKeyPath:@"_relativeBooks._name"];
        NSLog(@"%@",names);

        NSArray *names2 = [releBooks valueForKeyPath:@"_name"];
        NSLog(@"%@",names2);

        //运算, 运算的字段必须是数值类型NSNumber或者基本数据类型,计算的结果是NSNumber
        //运算关键字sum、min、max、avg、count
        NSNumber *sum = [book valueForKeyPath:@"_relativeBooks.@sum.price"];
        NSLog(@"sum: %@",sum);

    }
    return 0;
}

KVO的基本概念

·基本概念

键-值观察是一种使对象获取其他对象的特定属性变化的通知机制。

控制器层的绑定技术就是严重依赖键-值观察获得模型层和控制器层的变化通知 的。对于不依赖控制器层类的应用程序,键-值观察提供了一种简化的方法来实现 检查器并更新用户界面值。

与 NSNotification不同,键-值观察中并没有所谓的中心对象来为所有观察者提 供变化通知。取而代之地,当有变化发生时,通知被直接发送至处于观察状态的对 象。NSObject提供这种基础的键-值观察实现方法,你几乎不用重写该方法。

你可以观察任意对象属性,包括简单属性,对一或是对多关系。对多关系的观察 者将会被告知发生变化的类型-也就是任意发生变化的对象。

键-值观察为所有对象提供自动观察兼容性。你可以通过禁用自动观察通知并实现 手动通知来筛选通知。

·注册观察者

为了正确接收属性的变更通知,观察对象必须首先发送一个 addObserver:forKeyPath:options:context:消息至被观察对象,用以传送观察 对象和需要观察的属性的关键路径,以便与其注册。选项参数指定了发送变更通知 时提供给观察者的信息。使用NSKeyValueObservingOptionOld选项可以将初始 对象值以变更字典中的一个项的形式提供给观察者。指定 NSKeyValueObservingOptionNew选项可以将新的值以一个项的形式添加至变更字典。你可以使用逐位“|”这两个常量来指定接收上述两种类型的值。

·示例:

[child addObserver:self forKeyPath:@"tired" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];

·接受变更通知

当监听的属性发生变动时,观察者收到一 observeValueForKeyPath:ofObject:change:context:消息, 观察者必须实现这 一方法。触发观察通知的对象和键路径、包含变更细节的字典,以及观察者注册时提交的上下文指针均被提交给观察者。

·示例:

 - (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)c{
    if ([keyPath isEqual:@"key"]) {
        NSLog(@"");
    } 
}

·移除观察者身份

你可以发送一条指定观察方对象和键路径的removeObserver:forKeyPath:消息 至被观察的对象,来移除一个键-值观察者。(当我们达到目的时)

·示例:

- (void)dealloc {
    [_child removeObserver:self forKeyPath:@"happyVal"];
    [_child release];
    [super dealloc];
}

谓词的基本概念

·概念

cocoa中提供了NSPredicate类,指定过滤器的条件。将符合条件的对象保留下来。

·创建谓词

/**** 设置谓词条件 ****/
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"age <= 28"]; 
for (Person *person in array) {
    // 表示指定的对象是否满足谓词条件
    if ([predicate evaluateWithObject:person]) {
      //NSLog(@"person name : %@", person.name);
    } 
}
/**** 返回个符合谓词条件的数组 ****/
NSArray *newArray = [array filteredArrayUsingPredicate:predicate];
for (Person *person in newArray) {
    //NSLog(@"person name : %@", [person valueForKey:@"_name"]);
}
 /**** 格式占位符号 ****/
NSPredicate *pre = [NSPredicate predicateWithFormat:@" age <= %d", 30]; 
NSArray *array2 = [array filteredArrayUsingPredicate:pre];
for (Person *person in array2) {
     //NSLog(@"person name 2 %@", [person 
     valueForKey:@"_name"]);
}

·逻辑运算符

/**** 运算符号 的加入 谓词不区分大小 && AND || OR ****/
NSPredicate *pre3 = [NSPredicate predicateWithFormat:@"name > 'bruse' && age < %d", 30];
NSArray *array4 = [array filteredArrayUsingPredicate:pre3];

·IN

/**** 关键字 注意字符串 定要添加'' ****/
NSPredicate *pre4 = [NSPredicate predicateWithFormat:@"self.name IN {'rose', 'bruse'}"];
NSArray *array5 = [array filteredArrayUsingPredicate:pre4]; NSLog(@"person name : %@", [array5 valueForKey:@"_name"]);

·以**开始——BEGINSWITH

/**** BEGINSWITH 检查某个字是否以**开头 ****/
NSPredicate *pre5 = [NSPredicate predicateWithFormat:@"self.name BEGINSWITH 'J'"];
NSArray *array6 = [array filteredArrayUsingPredicate:pre5]; NSLog(@"person name : %@", [array6 valueForKey:@"name"]);

·以**结束——ENDSWITH

/**** ENDSWITH 检查某个字符是以**结尾 ****/
NSPredicate *pre6 = [NSPredicate predicateWithFormat:@"self.name endswith 'e'"];
NSArray *array7 = [array filteredArrayUsingPredicate:pre6]; NSLog(@"array7 : %@", [array7 valueForKey:@"name"]);

·包含——CONTAINS

/**** CONTAINS 检查包含某个字符 ****/
NSPredicate *pre8 = [NSPredicate predicateWithFormat:@"self.name CONTAINS '小'"];
NSArray *array8 = [array filteredArrayUsingPredicate:pre8]; 
NSLog(@"array8 : %@", [array8 valueForKey:@"name"]);

·模糊查询——Like

/**** Like 检查包含某个字符 ****/
NSString *s = [NSString stringWithFormat:@"name like '*%@*'",@"a"]; 
NSPredicate *predicate = [NSPredicate predicateWithFormat:s]; 
NSLog(@"array8 : %@", [array8 valueForKey:@"name"]);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值