KVC官方文档-键值编码指南第二部分3

Key-Value Coding Programming Guide 官方文档第二部分第3节
2018.9.20 第一次修正

iOS-KVC官方文档第二部分第3节

Key-Value Coding Fundamatals–Using Collection Operators

使用集合运算符

当你向符合键值编码的对象发送valueForKeyPath:消息时, 可以在键路径中嵌入集合运算符。集合运算符是一个小的关键字列表,前面带一个at符号(@), 它指定了getter应该执行的操作,以便在返回之前以某种方式操作数据。valueForKeyPath:NSObject默认实现。

当键路径包含集合运算符时, 运算符前面的键路径的任何部分 (称为左键路径) 指向相对于消息接收者操作的集合。如果将消息直接发送到集合对象 (例如NSArray实例), 则可以省略左键路径。操作符之后的键路径部分(称为右键路径)指定操作符应处理的集合中的属性。除了@count需要正确的键路径之外,所有集合运算符。图4-1说明了操作符键路径格式。

图 4-1运算符键路径格式

集合运算符展示了三种基本行为类型:

  • 聚合运算符以某种方式合并集合的对象,并返回通常与右键路径中指定的属性的数据类型匹配的单个对象。该@count运算符是一个例外,它没有右键路径并始终将返回一个NSNumber实例。

  • 数组运算符返回一个NSArray实例,该实例包含命名集合中保存的对象的某个子集。

  • 嵌套操作符处理包含其他集合的集合,并根据操作符返回一个NSArrayNSSet实例,它以某种方式组合嵌套集合的对象。

示例数据

下面描述包括演示如何调用每个运算符的代码段,以及执行此操作的结果。这依赖于BankAccount类 (在[列表 2-1]中显示), 它是一个保存Transaction对象的数组。其中每一个都代表一个简单的checkbook条目, 如清单 4-1中所声明的那样。

清单 4-1Transaction对象的接口声明

@interface Transaction : NSObject

@property (nonatomic) NSString* payee;   // To whom
@property (nonatomic) NSNumber* amount;  // How much
@property (nonatomic) NSDate* date;      // When

@end

为了便于讨论, 假定BankAccount实例具有一个使用表4-1中显示的数据填充的交易数组, 并且您可以从BankAccount对象内部进行调用。

表 4-1Transactions对象的示例数据

payee amount date
Green Power $120.00 Dec 1, 2015
Green Power $150.00 Jan 1, 2016
Green Power $170.00 Feb 1, 2016
Car Loan $250.00 Jan 15, 2016
Car Loan $250.00 Feb 15, 2016
Car Loan $250.00 Mar 15, 2016
General Cable $120.00 Dec 1, 2015
General Cable $155.00 Jan 1, 2016
General Cable $120.00 Feb 1, 2016
Mortgage $1,250.00 Jan 15, 2016
Mortgage $1,250.00 Feb 15, 2016
Mortgage $1,250.00 Mar 15, 2016
Animal Hospital $600.00 Jul 15, 2016

聚合运算符

聚合运算符处理arrayset属性, 从而生成反映集合某些方面的单个值。

@avg

当指定@avg运算符时, valueForKeyPath:读取集合中每个元素的右键路径指定的属性, 将其转换为double (nil值用0替代), 并计算这些值的算术平均值。
然后它返回存储在NSNumber实例中的结果。

获取表 4-1中示例数据之间的平均交易记录金额:

NSNumber *transactionAverage = [self.transactions valueForKeyPath:@"@avg.amount"];

transactionAverage的格式化的结果为 $ 456.54。

@count

指定@count运算符时, valueForKeyPath:返回一个包含集合中的对象个数的NSNumber实例。右键路径 (如果存在) 将被忽略。

在transactions中获取Transaction对象的数目:

NSNumber *numberOfTransactions = [self.transactions valueForKeyPath:@"@count"];

numberOfTransactions的值为13。

@max

指定@max运算符时, valueForKeyPath:在由右键路径命名的集合项之间进行搜索, 并返回最大值。搜索使用compare:方法进行比较, 该方法由许多Foundation类(例如NSNumber类)定义。因此, 由右键路径指示的属性必须包含一个对此消息有意义响应的对象。搜索忽略值为nil的集合项。

在表 4-1中列出的交易记录中, 获取日期值 (即最新交易记录的日期) 的最大数量:

NSDate *latestDate = [self.transactions valueForKeyPath:@"@max.date"];

latestDate的值为 Jul 15, 2016.

@min

指定@min运算符时, valueForKeyPath:在由右键路径命名的集合项之间进行搜索, 并返回最小值。搜索使用compare:方法进行比较, 许多基础类 (如NSNumber类) 中都有定义。因此, 由右键路径指示的属性必须持有对此消息有意义响应的对象。搜索忽略值为nil的集合项。

在表 4-1中列出的事务中, 获取日期值 (即最早的事务的日期) 的最短时间。

NSDate *earliestDate = [self.transactions valueForKeyPath:@"@min.date"];

earliestDate的值为 Dec 1, 2015.

@sum

指定@sum运算符时, valueForKeyPath:读取集合中每个元素的右键路径指定的属性, 将其转换为double (nil值替换为 0), 并计算总和。然后返回存储在NSNumber实例中的结果。

获取表 4-1中示例数据之间的交易记录金额的总和:

NSNumber *amountSum = [self.transactions valueForKeyPath:@"@sum.amount"];

amountSum的结果为 $ 5935.00。

数组运算符

数组运算符使valueForKeyPath:返回与右键路径指示的特定对象集相对应的对象数组。

重要
在使用数组运算符时, 如果有任何叶(leaf)对象为nil, 则valueForKeyPath:方法将引发异常。

@distinctUnionOfObjects

指定@distinctUnionOfObjects运算符时, valueForKeyPath:将创建并返回一个数组, 该数组包含与右键路径指定的属性对应的集合的不同对象。

获取transactions中的交易记录的payee属性值的集合, 并省略重复值:

NSArray *distinctPayees = [self.transactions valueForKeyPath:@"@distinctUnionOfObjects.payee"];

生成的distinctPayees数组包含以下每一个字符串实例:Car Loan, General Cable, Animal Hospital, Green Power, Mortgage

注意
@unionOfObjects运算符提供类似的行为, 但不删除重复的对象。

@unionOfObjects

指定@unionOfObjects运算符时, valueForKeyPath:将创建并返回一个数组, 该数组包含与由右键路径指定的属性对应的集合的所有对象。与@distinctUnionOfObjects不同, 不会删除重复对象。

获取transactions中的交易记录的payee属性值的集合:

NSArray *payees = [self.transactions valueForKeyPath:@"@unionOfObjects.payee"];

生成的payees数组包含以下字符串:Green Power, Green Power, Green Power, Car Loan, Car Loan, Car Loan, General Cable, General Cable, General Cable, Mortgage, Mortgage, Mortgage, Animal Hospital.记录了重复值。

注意
@distinctUnionOfArrays运算符类似, 但删除重复的对象。

嵌套运算符

嵌套运算符对嵌套集合进行操作, 集合本身的每个条目都包含一个集合。

重要
如果在使用嵌套运算符时, 有任何叶(leaf)对象为nil, 则valueForKeyPath:方法将引发异常。

对于下面的说明, 请看第二个称为moreTransactions的数据数组, 其中填充了表 4-2中的数据, 并与原来的transactions数组一起插入嵌套数组:

NSArray* moreTransactions = @[<# transaction data #>];
NSArray* arrayOfArrays = @[self.transactions, moreTransactions];

表 4-2 moreTransactions数组中假设的Transaction数据

payee amount date
General Cable - Cottage $120.00 Dec 18, 2015
General Cable - Cottage $155.00 Jan 9, 2016
General Cable - Cottage $120.00 Dec 1, 2016
Second Mortgage $1,250.00 Nov 15, 2016
Second Mortgage $1,250.00 Sep 20, 2016
Second Mortgage $1,250.00 Feb 12, 2016
Hobby Sho $600.00 Jun 14, 2016

@distinctUnionOfArrays

指定@distinctUnionOfArrays运算符时, valueForKeyPath:创建并返回一个数组, 其中包含与右键路径指定的属性相对应的所有集合的组合的不同对象。

arrayOfArrays中的所有数组中获取payee属性的不同值:

NSArray *collectedDistinctPayees = [arrayOfArrays valueForKeyPath:@"@distinctUnionOfArrays.payee"];

生成的collectedDistinctPayees数组包含以下值: Hobby Shop, Mortgage, Animal Hospital, Second Mortgage, Car Loan, General Cable - Cottage, General Cable, Green Power

注意
@unionOfArrays运算符类似, 但不移除重复对象。

@unionOfArrays

指定@unionOfArrays运算符时, valueForKeyPath:创建并返回一个数组, 其中包含与由右键路径指定的属性相对应的所有集合的组合的所有对象, 而不删除重复项。

arrayOfArrays中的所有数组中获取payee属性的值:

NSArray *collectedPayees = [arrayOfArrays valueForKeyPath:@"@unionOfArrays.payee"];

生成的collectedPayees数组包含以下值:Green Power, Green Power, Green Power, Car Loan, Car Loan, Car Loan, General Cable, General Cable, General Cable, Mortgage, Mortgage, Mortgage, Animal Hospital, General Cable

注意
@distinctUnionOfArrays运算符类似, 但移除重复对象。

@distinctUnionOfSets

当指定@distinctUnionOfSets运算符时, valueForKeyPath:创建并返回一个NSSet对象, 其中包含与由右键路径所指定的属性相对应的所有集合组合的不同对象。

此运算符的行为与@distinctUnionOfArrays类似, 只是它需要一个包含NSSet实例的NSSet实例对象, 其中, 而不是包含NSArray实例的NSArray实例对象。此外, 它还返回一个NSSet实例。假设示例数据已存储在集合而不是数组中, 则示例调用和结果与@distinctUnionOfArrays中显示的相同。

由于笔者水平有限,文中如果有错误的地方,或者有更好的方法,还望大神指出。
附上本文的所有 demo 下载链接,【GitHub】
如果你看完后觉得对你有所帮助,还望在 GitHub 上点个 star。赠人玫瑰,手有余香。