valueForKeyPath 妙用

当你对一个对象(集合/数组)发送了valueForKeyPath:消息的时候,集合操作允许你通过嵌入关键字的形式作出相应的操作. 集合操作符是一个以@开头的特殊字符串. for example: @distinctUnionOfObjects.self 无论什么时候你在key path中看见了@,它都代表了一个特定的集合方法,其结果可以被返回或者链接.

开始前,我们先定义一个产品模型ProductModel并准备好数据:

@interface ProductModel : NSObject
@property (nonatomic, strong) NSString *name;//产品名称
@property (nonatomic, assign) CGFloat price;//产品价格
@end

//模拟数据
ProductModel *productA = [[ProductModel alloc] init];
productA.price = 99.0;
productA.name = @"iPod";
    
ProductModel *productB = [[ProductModel alloc] init];
productB.price = 199.0;
productB.name = @"iMac";
    
ProductModel *productC = [[ProductModel alloc] init];
productC.price = 299.0;
productC.name = @"iPhone";
    
ProductModel *productD = [[ProductModel alloc] init];
productD.price = 199.0;
productD.name = @"iPhone";

KVC 集合操作符类型

  • Simple Collection Operators 简单的集合操作符
  • Object Operators 对象操作符
  • Array and Set Operators 数组/集合操作符

简单的集合操作

  • @count返回一个值为集合中对象总数的 NSNumber 对象
  • @avg首先把集合中的对象都转换成 double 类型,然后计算其平均值,并返回这个平均值的 NSNumber 对象
  • @max使用compare:方法来确定最大值,并返回最大值的 NSNumber 对象,所以为了保证其正常的比较,集合中的所有对象必须支持和另一个对象的比较,保证其可比性.
  • @min原理和@max一样,返回集合中最小值的 NSNumber 对象
  • @sum首先把集合中的对象都转换成 double 类型,然后计算其总和,并返回这个总和的 NSNumber 对象

NOtice:所有的集合操作,除了@ count 外,其他的都需要有右边的 keypath(一般为属性名),@count右边的 keypath可写可不写

NSArray *product = @[productA, productB, productC, productD];
NSNumber *count = [product valueForKeyPath:@"@count.price"];
NSNumber *avg = [product valueForKeyPath:@"@avg.price"];
NSNumber *max = [product valueForKeyPath:@"@max.price"];
NSNumber *min = [product valueForKeyPath:@"@min.price"];
NSNumber *sum = [product valueForKeyPath:@"@sum.price"];
NSLog(@"count:%@, avg:%@, max:%@, min:%@, sum:%@", count, avg, max, min, sum); // count:4, avg:199, max:299, min:99, sum:796

Notice:若操作对象(数组/集合)内的元素本身就是 NSNumber 对象,那么可以这样写.

NSArray *array = @[@(productA.price), @(productB.price), @(productC.price), @(productD.price)];
NSNumber *count = [array valueForKeyPath:@"@count"];
NSNumber *avg = [array valueForKeyPath:@"@avg.self"];
NSNumber *max = [array valueForKeyPath:@"@max.self"];
NSNumber *min = [array valueForKeyPath:@"@min.self"];
NSNumber *sum = [array valueForKeyPath:@"@sum.self"];
NSLog(@"count:%@, avg:%@, max:%@, min:%@, sum:%@", count, avg, max, min, sum);//count:4, avg:199, max:299, min:99, sum:796

对象操作符

  • unionOfObjects:获取数组中每个对象的属性的值,放在一个数组中并返回,但不会去重
  • distinctUnionOfObjects:获取数组中每个对象的属性的值,放在一个数组中并返回,会对数组去重;常用来对数组元素去重,快捷高效
NSArray *unionOfObjects = [product valueForKeyPath:@"@unionOfObjects.name"];
NSArray *distinctUnionOfObjects = [product valueForKeyPath:@"@distinctUnionOfObjects.name"];
NSLog(@"unionOfObjects : %@", unionOfObjects);//iPod,iMac,iPhone,iPhone
NSLog(@"distinctUnionOfObjects : %@", distinctUnionOfObjects);//iPhone,iPod,iMac

数组/集合操作符(可粗略理解为二维数组/集合的展开)

  • @distinctUnionOfArrays返回操作对象(且操作对象必须是数组/集合)中的所有元素,即返回这个数组本身,会去重
  • unionOfArrays首先获取操作对象(且操作对象必须是数组/集合)中的所有元素,然后装到一个新的数组中并返回,不会对这个数组去重

Notice: 操作对象中的元素必须是数组

NSArray *distinctUnionOfArrays = [@[product, product] valueForKeyPath:@"@distinctUnionOfArrays.price"];
NSArray *unionOfArrays = [@[product, product] valueForKeyPath:@"@unionOfArrays.price"];
NSLog(@"distinctUnionOfArrays : %@", distinctUnionOfArrays);//299,99,199
NSLog(@"unionOfArrays : %@", unionOfArrays);//99,199,299,199,99,199,299,199
  • distinctUnionOfSets返回操作对象(且操作对象必须是数组/集合)中数组/集合的所有对象,返回值为集合,因为集合不能包含重复值,所以它只能有 distinct操作 Notice: 操作对象中的元素必须是集合
NSSet *setA = [NSSet setWithObjects:productA, productB, nil];
NSSet *setB = [NSSet setWithObjects:productC, productD, nil];
NSSet *set = [NSSet setWithObjects:setA, setB, nil];

NSSet *allSet = [set valueForKeyPath:@"@distinctUnionOfSets.name"];
NSLog(@"distinctUnionOfSets: %@", allSet);//iPhone,iPod,iMac

具体的应用举例

删除重复值

NSArray *array = @[@"name", @"w", @"aa", @"zxp", @"aa"];
 //返回的是一个新的数组
 NSArray *newArray = [array valueForKeyPath:@"@distinctUnionOfObjects.self"];
 NSLog(@"%@", newArray);
同样可以嵌套使用,先剔除name对应值的重复数据再取值
NSArray *array = @[
@{@"title":@"zxp",@"name":@"zhangxiaoping"},
@{@"title":@"zxp2",@"name":@"zhangxiaoping2"},
@{@"title":@"zxp",@"name":@"zhangxiaoping3"},
@{@"title":@"zxp",@"name":@"zhangxiaoping"}];
//根据name字段,来进行重复删除。
NSArray *newArray = [array valueForKeyPath:@"@distinctUnionOfObjects.name"];//如果要根据title字段来删除重名的写法为`@distinctUnionOfObjects.title`                  
NSLog(@"%@", newArray);
/*print:
(
    zhangxiaoping3,
    zhangxiaoping2,
    zhangxiaoping
)
是一个字符串数组
*/

获取数组里的,最大、最小、平均、求和

NSArray *array = @[@1, @2, @3, @4, @10];

NSNumber *sum = [array valueForKeyPath:@"@sum.self"];
NSNumber *avg = [array valueForKeyPath:@"@avg.self"];
NSNumber *max = [array valueForKeyPath:@"@max.self"];
NSNumber *min = [array valueForKeyPath:@"@min.self"];

或者指定输出类型

NSNumber *sum = [array valueForKeyPath:@"@sum.floatValue"];
NSNumber *avg = [array valueForKeyPath:@"@avg.floatValue"];
NSNumber *max = [array valueForKeyPath:@"@max.floatValue"];
NSNumber *min = [array valueForKeyPath:@"@min.floatValue"];

NSDictionary 获取相应的 key

NSArray *array = @[@{@"name" : @"cookeee",@"code" : @1},
                @{@"name": @"jim",@"code" : @2},
                @{@"name": @"jim",@"code" : @1},
                @{@"name": @"jbos",@"code" : @1}];
NSLog(@"%@", [array valueForKeyPath:@"name"]);

进行实例方法的调用

NSArray *array = @[@"name", @"w", @"aa", @"ZXPing"]; 
NSLog(@"%@", [array valueForKeyPath:@"uppercaseString"]);

改变 UITextfield 的 placeholder 的颜色

[searchField setValue:[UIColor whiteColor] forKeyPath:@"_placeholderLabel.textColor"];

比起重写- (void)drawPlaceholderInRect:(CGRect)rect;要方便很多

我怎样才能最容易地展平一个三维数组

NSArray *threeDimensionalArray = @[ 
@[  
    @[ @"Peter", @"Paul", @"Mary" ], @[ @"Joe", @"Jane" ] 
    ], 
@[ 
    @[ @"Alice", @"Bob" ] 
    ] 
];
//我希望得到
@[ @"Peter", @"Paul", @"Mary", @"Joe", @"Jane", @"Alice", @"Bob" ] 

键值编码(KVC)集合运算符@unionOfArrays展平一个级别的数组,因此将其应用两次会产生所需的结果。

集合运算符(@count除外)需要一个集合属性的关键路径,由于我们的对象本身已经是数组(因此集合),关键路径必须是self。

因此,我们需要与self关键路径应用@unionOfArrays两次,得到以下KVC调用展平三维数组:

NSArray *flattenedArray = [threeDimensionalArray valueForKeyPath: @"@unionOfArrays.self.@unionOfArrays.self"]; 

获得 NSDictionary NSArray 的值列表

我有以下 NSArray:

NSArray myArray = @[@{@300:@"5 min"},
                    @{@900:@"15 min"},
                    @{@1800:@"30 min"},
                    @{@3600:@"1 hour"}];

我想我的字典的值的列表︰
@[@"5 min",@"15 min",@"30 min",@"1 hour"]
和我的字典的键的列表︰
@[@300, @900, @1800, @3600]

NSArray *values = [myArray valueForKeyPath: @"@unionOfArrays.@allValues"];

NSArray *keys   = [myArray valueForKeyPath: @"@unionOfArrays.@allKeys"];

一个简短的解释可能是顺序︰

我们想要的结果是

所有的值 (或键) 的每个词典,获取数组的数组的值 (或键)
然后我们要拼合到单个阵列中的这些阵列。
要获得使用 KVC 词典的所有值 (或键),特殊键是 @allValues 或 @allKeys ,分别。

@unionOfArrays阵列联盟获得从它,即,后面的表达式的运算符使展平它到你想要的数组。

转载于:https://my.oschina.net/sshsxl/blog/1928633

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值