博客> 移动开发(IOS) – Objective-C-10-KVC、谓词、KVO与通知
移动开发(IOS) – Objective-C-10-KVC、谓词、KVO与通知
2017-10-15 10:07 评论:0 阅读:243 诸葛亮倒骑小毛驴
ios 移动开发(IOS) Objective-C-10-KVC 谓词 KVO与通知

移动开发(IOS) – Objective-C-10-KVC、谓词、KVO与通知 1.KVC

1.1.基本概念

1.1.1.KVC 是 KeyValue Coding 的简称,它是一种可以直接通过字符串的名字( key ) 来访问类属性的机制。

1.1.2.使用该机制不需要调用存取方法和变量实例就可访问对象属性。

1.1.3.本质上讲,键-值编码定义了你的程序存取方法需要实现的样式及方法签名。

1.1.4.在应用程序中实现键-值编码兼容性是一项重要的设计原则。存取方法可以加强合适的数据封装,而键-值编码方法在多数情况下可简化程序代码。

1.1.5.键-值 编码方法在 Objective-C 非标准协议(类目) NSKeyValueCoding 中 被声明,默认的实现方法由 NSObject 提供。

1.1.6.键-值编码支持带有对象值的属性,同时也支持纯数值类型和结构。非对象参数和返回类型会被识别并自动封装/解封。

1.1.7.使用 KVC 为对象赋值或者取值时,需要知道准确的键值, 相比较点语法,KVC 是一种间接的传递方式,这种方式有利于对象解耦,让对象彼此之间的耦合度不会太高。

1.2.设置和访问

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

1 2 3 4

Person jack = [[Person alloc] init]; NSMutableString name = [[NSMutableString alloc] initWithFormat:@"jack"]; [jack setValue:name forKey:@"name"]; //通过KVC设值 NSLog(@"Jack's name : %@", [jack valueForKey:@"name"]);//通过KVC取值

1.2.2.是否存在 setter、getter 方法, 若存在优先调用相应方法;若不存在,它将在内部查找名为 _key 或 key 的实例变量。

1.2.3.通过 KVC 设置对象,此对象会 retain。

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

1.2.5.赋值语句 setValue:forKey: 是给对象当前的属性赋值,而 setValue:forKeyPath: 是按照对象的层级关系为其中的属性赋值 。 forKeyPath可以替代forKey,但是forKey不能替代forKeyPath。

1.2.6.setValuesForKeysWithDictionary: 可以从 plist 文件中读取对应的数据字典,对对象属性赋值。

1.3.批处理

1 2 3 4 5 6 7 8

//同时获取 Student 的 age 和 name NSArray keys = [NSArray arrayWithObjects:@"name", @"age", nil]; NSDictionary dict = [student dictionaryWithValuesForKeys:keys]; //同时设置 Student 的 age 和 name NSArray keys = [NSArray arrayWithObjects:@"name", @"age", nil]; NSArray values = [NSArray arrayWithObjects:@"MJ", [NSNumber numberWithInt:16], nil]; NSDictionary *dict = [NSDictionary dictionaryWithObjects:values forKeys:keys]; [student setValuesForKeysWithDictionary:dict];

1.4.路径

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

1

[book setValue:@"比尔" forKeyPath:@"author.name"];

1

NSNumber *price=[book valueForKeyPath:@"relativeBooks.price"]

1.4.数组的整体操作

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

1 2 3 4

// 获取 Student 中所有 Book 的 name NSArray names = [student.books valueForKeyPath:@"name"]; 或者 NSArray names = [student valueForKeyPath:@"books.name"]; //注意:不能在键路径中为数组添加索引,比如 @"books[0].name"

1.5.KVC的简单运算

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

//count

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

2.谓词

2.1.基本概念

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

2.2.创建谓词:

1 2 3 4 5 6 7 8 9 10 11 12 13

// 设置谓词条件 NSPredicate predicate = [NSPredicate predicateWithFormat:@"age <= 28"]; for (Person person in array) { // 表⽰指定的对象是否满⾜谓词条件 if ([predicate evaluateWithObject:person]) { NSLog(@"person's name : %@", person.name); } }

// 返回⼀个符合谓词条件的数组 NSArray newArray = [array filteredArrayUsingPredicate: predicate]; for (Person person in newArray) { NSLog(@"person's name : %@", [person valueForKey:@"_name"]); }

2.3.格式占位符

1 2 3 4 5 6

// 格式占位符号 NSPredicate pre = [NSPredicate predicateWithFormat:@" age <= %d", 30]; NSArray array2 = [array filteredArrayUsingPredicate:pre]; for (Person *person in array2) { NSLog(@"person's name : %@", [person valueForKey:@"_name"]); }

2.4.运算符

2.4.1.逻辑运算符

1 2 3

// 运算符号 && AND || OR NSPredicate pre = [NSPredicate predicateWithFormat:@"name > 'bruse' && age < %d", 30]; NSArray array = [array filteredArrayUsingPredicate:pre];

2.4.2.IN

1 2 3 4

//注意字符串一定要添加'' NSPredicate pre = [NSPredicate predicateWithFormat:@"self.name IN {'rose', 'bruse'}"];//self.可以省略 NSArray array = [array filteredArrayUsingPredicate:pre]; NSLog(@"person's name : %@", [array valueForKey:@"_name"]);

2.4.3.以…开始: BEGINSWITH

1 2 3 4

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

2.4.4.以…结束: ENDSWITH

1 2 3 4

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

2.4.5.包含: CONTAINS

1 2 3 4

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

2.4.6.like

1 2 3 4

// like :匹配任意多个字符 ?:表示一个字符 (正则) NSPredicate pre = [NSPredicate predicateWithFormat:@"name like '?a'"]; NSArray array = [array filteredArrayUsingPredicate:pre]; NSLog(@"person's name : %@", [array valueForKey:@"name"]);

3.KVO

3.1.基本概念

3.1.1.Key Value Observing,直译为:基于键值的观察者。它提供一种机制,当 指定的对象的属性被修改后,则对象就会接受到通知。简单的说就是每次指定的被 观察的对象的属性被修改后,KVO就会自动通知相应的观察者了。

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

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

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

3.1.5.不能观察已经被释放的对象,如果要观察,需要是强应用对象,或者被其他对象强应用的对象。

3.2.注册观察者

为了正确接收属性的变更通知,被观察者必须首先调用 addObserver:forKeyPath:options:context: 方法进行注册:

1 2 3 4 5 6 7 8 9 10 11

/* anObserver :监听器对象

  • keyPath :监听的属性
  • options :决定了当属性改变时,要传递什么数据给监听器 / -(void)addObserver:(NSObject )anObserver forKeyPath:(NSString )keyPath options:(NSKeyValueObservingOptions)options context:(void )context

/* 使用NSKeyValueObservingOptionOld选项,可以将改变之前的值传递给观察者。(以变更字典中的一个项的形式)

  • 指定 NSKeyValueObservingOptionNew选项,可以将改变的新值传递给观察者。
  • 可以使用逐位“|”这两个常量,来指定同时传递上述两种类型的值。 */ [_child addObserver:self forKeyPath:@"tired" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];

3.3.接受变更通知

当对象的一个被观察属性发生变动时,观察者收到一个 observeValueForKeyPath:ofObject:change:context:消息。所有观察者都必须 实现这一方法:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

/*

  • keyPath : 键路径
  • object : 被观察者
  • change : 包含变更细节的字典
  • context : 注册观察者时提交的上下文指针,可以为任意类型的参数 / - (void)observeValueForKeyPath:(NSString )keyPath ofObject:(id)object change:(NSDictionary )change context:(void )c{ if ([keyPath isEqual:@"key"]) { NSLog(@""); } } // observeValueForKeyPath 方法是 NSObject 的分类,意味着可以观察任何对象。

3.4.移除观察者

当观察者销毁时,或达到目的无需再使用 KVO 时,应该将观察者移除:

1

[_child removeObserver:self forKeyPath:@"key"];

4.通知

4.1.与 KVO 不同:

4.1.1.自定触发通知,不像 KVO,属性值一经改变便触发通知。

4.1.2.回调方法自定,不像 KVO,需要重写一个方法。

4.1.3.观察者和被观察者都可以没有对方的引用,两者可以毫无关系。

4.2.监听通知

1 2 3 4 5 6 7 8 9 10

/*

  • self : 观察者对象为自身
  • @selector(notificationAction:) : 当收到通知时,调用notificationAction:方法
  • @"hapyValueNotification" : 监听通知名为@"hapyValueNotification"
  • nil : 传递参数为nil */ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notificationAction:) name:@"hapyValueNotification" object:nil];

1 2 3 4 5 6 7 8

//收到通知时的回调方法

  • (void)notificationAction:(NSNotification )notification { Children child = notification.object; [self playWith:child]; }
  • (void)playWith:(Children *)child { child.hapyValue = 100; };

4.3.发送通知

1 2 3 4 5

/*

  • @"hapyValueNotification" : 发送通知名为@"hapyValueNotification"
  • self : 传递参数为self,自身对象 */ [[NSNotificationCenter defaultCenter] postNotificationName:@"hapyValueNotification" object:self];

4.4.移除通知

当观察者销毁时,或达到目的无需再使用 通知 时,应该将通知移除:

1 2

//移除当前对象上指定的通知,通知名:@"hapyValueNotification" [[NSNotificationCenter defaultCenter] removeObserver:self name:@"hapyValueNotification" object:nil];

1 2

//移除当前对象上所有的通知 [[NSNotificationCenter defaultCenter] removeObserver:self];

收藏
2
sina weixin mail 回到顶部