iOS KVC 集合操作
进一步阅读之前,可以先思考这个问题: 存在数组
@[@(90), @(31), @(65), @(78), @(76)]
,如何取出数组中的最大值或者最小值?
KVC 的集合操作符可使用键路径和操作运算作用于集合中的所有元素。本文将描述一些可用的集合操作。
KVC 的集合操作符实际上就是一些特殊的键路径,以参数的形式传递给 valueForKeyPath:
方法。集合操作是以 @*
开始的字符串, 也可理解为: KVC集合操作符允许在
valueForKeyPath:
方法中使用 key path
符号在一个集合中执行方法。无论什么时候你在 key path
中看见了@*,它都代表了一个特定的集合方法,其结果可以被返回或者链接,就像其他的
key path 一样。下图就是集合操作符的格式:
其中左边的键路径(keypathToCollection)指定了相对消息接收者的 NSArray 或者 NSSet,右边的键路径(keypathToProperty)指定了相对于集合内对象的键路径,集合操作作用于该键路径。
除了 @count
外的所有集合操作,都要求在集合操作右边有一键路径(keypathToProperty)。
集合操作返回的对象值决定于集合操作的类型:
- 简单类型的集合操作符,返回 strings, numbers, dates, 其值由右侧的键路径决定(见简单集合操作符)
- 对象操作符,返回 NSArray 对象实例(见 对象操作符)
- 数组和集合操作符,返回的是一个 array 或者 set 对象(见 数组和集合操作符)
示例数据
以下示例会用到一些数据,先看看示例数据。想象一个 Product 类和由 Product 类对象所组成的 products 数组:
1 | @interface Product : NSObject |
键-值 编码会在必要的时候把基本数据类型的数据自动装箱和拆箱到 NSNumber 或者 NSValue 中来确保一切工作正常。
products 数组中 Product 类对象所使用数据如下:
Name | Price | Launch Date |
---|---|---|
iPhone5 | $199 | September 21, 2012 |
iPhone5 | $199 | September 21, 2012 |
iPhone5 | $199 | September 21, 2012 |
iPad Mini | $329 | November 2, 2012 |
MacBook Pro | $1699 | June 11,2012 |
MacBook Pro | $1699 | June 11,2012 |
iMac | $1299 | November 2, 2012 |
还有另一个数组 products2,它内部元素也是 Product 类对象,数据如下:
Name | Price | Launch Date |
---|---|---|
iPhone5 | $199 | September 21, 2012 |
iPad Mini | $329 | November 2, 2012 |
MacBook Pro | $1699 | June 11,2012 |
iMac | $1299 | November 2, 2012 |
iMac | $1299 | November 2, 2012 |
iMac | $1299 | November 2, 2012 |
简单集合操作符
简单集合操作符作用于 array 或者 set
中相对于集合操作符右侧的属性。包括 @avg
,
@count
, @max
, @min
,
@sum
.
- @avg 操作符将集合中属性键路径所指对象转换为 double, 计算其平均值,返回该平均值的 NSNumber 对象。当均值为 nil 的时候,返回 0.
- @count 操作符返回集合中对象总数的 NSNumber 对象。操作符右边没有键路径。
- @max
操作符比较由操作符右边的键路径指定的属性值,并返回比较结果的最大值。最大值由指定的键路径所指对象的
compare:
方法决定,因此参加比较的对象必须支持和另一个对象的比较。如果右侧键路径所指对象值为 nil, 则忽略,不影响比较结果。 - @min 和 @max 一样,但是返回的是集合中的最小值。
- @sum 返回右侧键路径指定的属性值的总和。每一个比较值都转换为 double,然后计算值的总和,最后返回总和值的 NSNumber 对象。如果右侧键路径所指对象值为 nil,则忽略。
1 | [products valueForKeyPath:@"@count"]; // 7 |
Pro提示:你可以简单的通过把 self 作为操作符后面的 key path 来获取一个由 NSNumber 组成的数组或者集合的总值,例如对于数组 @[@(1), @(2), @(3)] 可使用
valueForKeyPath:@"@max.self"
来获取最大值。
对象操作符
对象操作符包括 @distinctUnionOfObjects
和
@unionOfObjects
, 返回一个由操作符右边的 key path
所指定的对象属性组成的数组。其中 @distinctUnionOfObjects
会对数组去重,而 @unionOfObjects
不会。
1 | NSArray *unionOfObjects = [products valueForKeyPath:@"@unionOfObjects.name"]; // 1. |
unionOfObjects 中会包含 "iPhone5", "iPhone5","iPhone5", "iPad Mini", "MacBook Pro", "MacBook Pro", "iMac"
distinctUnionObjects 中会包含 "iPhone5", "iPad Mini", "MacBook Pro", "iMac", 相当于对 unionOfObjects 数组进行去重处理。
数组和集合操作符
数组和集合操作符作用对象是嵌套的集合,也就是说,是一个集合且其内部每个元素是一个集合。数组和集合操作符包括
@distinctUnionOfArrays
,@unionOfArrays
,@distinctUnionOfSets
:
- @distinctUnionOfArrays / @unionOfArrays 返回一个数组,其中包含这个集合中每个数组对于这个操作符右面指定的 key path 进行操作之后的值。 distinct 版本会移除重复的值。
- @distinctUnionOfSets 和 @distinctUnionOfArrays 差不多, 但是它期望的是一个包含着 NSSet 对象的 NSSet ,并且会返回一个 NSSet 对象。因为集合不能包含重复的值,所以它只有 distinct 操作。
假定有个 totalProducts 数组,其包含两个数组 products 和 products2,以下代码片段展示了 totalProducts 的创建。
1 | totalProducts = [NSMutableArray array]; |
其中 products 和 products2 中元素都是 Product 类对象,其内部数据使用的是示例数据的数据内容。
对于以下操作:
1 | NSArray *distinctUnionOfArrays = [totalProducts valueForKeyPath:@"@distinctUnionOfArrays.name"]; |
那么 unionOfArrays 中包含 "iPhone5", "iPhone5", "iPhone5", "iPad Mini", "MacBook Pro", "MacBook Pro", "iMac", "iPhone5", "iPad Mini", "MacBook Pro", "iMac", "iMac", "iMac" 共 13 个元素。而 distinctUnionOfArrays 中仅包含 "iPhone5", "iPad Mini", "MacBook Pro", "iMac" 共 4 个元素。
注意: 如果操作符右侧 key path 指定的对象为 nil,那么返回的数组中会包含 NSNull 对象.
参考:
目前已转行教育行业,欢迎加微信交流:CaryaLiu