美文网首页
OC由浅入深系列 之 KVC (二):集合代理对象

OC由浅入深系列 之 KVC (二):集合代理对象

作者: SimonMont | 来源:发表于2019-03-18 16:28 被阅读0次

一、什么是集合代理对象

假设我们有这样一个问题:我们有一NSMutableArray的对象,我们希望在往插入对象的时候出发KVO,改怎么实现呢?
我们知道KVO是通过隐式的创建一个子类,重写setter方法实现的(见KVO篇)。而往数组里插入,删除对象的时候是不会出发setter方法的,所以是触发不了KVO的。那么我们应该怎么解决呢? 那就是使用KVC的集合代理对象。既然是代理对象,那就不是对象本身了,而是一个代理对象。举个栗子:假设我们有个商品类:Product,我们需要通过 -valueForKey: 方法获取一个NSArray,NSSet或者NSOrderedSet的集合,而Product中并没有实现 -<key>方法 那么我们可以在Product类中这样写:

- (NSInteger)countOfContacts;
- (id)objectInContactsAtIndex:(NSInteger)index;

这样我们在调用[product valueForKey:@"contacts"]的时候就会返回给我们一个NSArray的代理对象(注意是代理对象哦,不一定是NSArray),我们可以像数组一样去操作这个对象。

如果对NSSet,NSOrderedSet 实现相同的功能,则需要实现如下方法:

NSArray NSSet NSOrderedSet
-countOf<Key> -countOf<Key> -countOf<Key>
-enumeratorOf<Key> -indexIn<Key>OfObject:
以下两者二选一 -memberOf<Key>:
-objectIn<Key>AtIndex: 以下两者二选一
-<key>AtIndexes: -objectIn<Key>AtIndex:
-<key>AtIndexes:
可选(增强性能)
-get<Key>:range: 可选(增强性能)
-get<Key>:range:

一句话概括集合代理对象就是:KVC通过上面表格里面的方法相互组合来完成集合具备的功能。

对于可变的集合还需要实现如下的功能方法:

NSMutableArray / NSMutableOrderedSet NSMutableSet
至少实现一个插入方法和一个删除方法 至少实现一个插入方法和一个删除方法
-insertObject:in<Key>AtIndex: -add<Key>Object:
-removeObjectFrom<Key>AtIndex: -remove<Key>Object:
-insert<Key>:atIndexes: -add<Key>:
-remove<Key>AtIndexes: -remove<Key>:
可选(增强性能)以下方法二选一 可选(增强性能)
-replaceObjectIn<Key>AtIndex:withObject: -intersect<Key>:
-replace<Key>AtIndexes:with<Key>: -set<Key>:

二、使用场景

1、KVO集合元素变化时,使用-mutableArrayValueForKey: 生成数组代理对象(这是个面试题)

 [product mutableArrayValueForKey:@"contacts"]  addObject:newcontact];      

mutableArrayValueForKey:会生成数组contactsde代理对象,当我们addObject的时候,会生成一个新的数组,代替原来的数组,这样就会触发KVO了。

2、以集合的方式操作操作非集合对象时,实现上面两个表格中的特定方法即可。这里放一个网上的例子:

@interface Primes : NSObject

@property (readonly, nonatomic, strong) NSArray *primes;

@end

@implementation Primes

static int32_t const primes[] = {
    2, 101, 233, 383, 3, 103, 239, 389, 5, 107, 241, 397, 7, 109,
    251, 401, 11, 113, 257, 409, 13, 127, 263, 419, 17, 131, 269,
    421, 19, 137, 271, 431, 23, 139, 277, 433, 29, 149, 281, 439,
    31, 151, 283, 443, 37, 157, 293, 449, 41, 163, 307, 457, 43,
    167, 311, 461, 47, 173, 313, 463, 53, 179, 317, 467, 59, 181,
    331, 479, 61, 191, 337, 487, 67, 193, 347, 491, 71, 197, 349,
    499, 73, 199, 353, 503, 79, 211, 359, 509, 83, 223, 367, 521,
    89, 227, 373, 523, 97, 229, 379, 541, 547, 701, 877, 1049,
    557, 709, 881, 1051, 563, 719, 883, 1061, 569, 727, 887,
    1063, 571, 733, 907, 1069, 577, 739, 911, 1087, 587, 743,
    919, 1091, 593, 751, 929, 1093, 599, 757, 937, 1097, 601,
    761, 941, 1103, 607, 769, 947, 1109, 613, 773, 953, 1117,
    617, 787, 967, 1123, 619, 797, 971, 1129, 631, 809, 977,
    1151, 641, 811, 983, 1153, 643, 821, 991, 1163, 647, 823,
    997, 1171, 653, 827, 1009, 1181, 659, 829, 1013, 1187, 661,
    839, 1019, 1193, 673, 853, 1021, 1201, 677, 857, 1031,
    1213, 683, 859, 1033, 1217, 691, 863, 1039, 1223, 1229,
};

- (NSUInteger)countOfPrimes;
{
    return (sizeof(primes) / sizeof(*primes));
}

- (id)objectInPrimesAtIndex:(NSUInteger)idx;
{
    NSParameterAssert(idx < sizeof(primes) / sizeof(*primes));
    return @(primes[idx]);
}

@end
我们将会运行以下代码:

Primes *primes = [[Primes alloc] init];
NSLog(@"The last prime is %@", [primes.primes lastObject]);

三、集合操作符

这部分内容不想赘述,以下部分类容参照https://www.jianshu.com/p/7675709d14a7 ,感谢这位作者付出。
集合操作:一个集合/数组通过调用valueForKeyPath:可允许一个集合中的对象属性根据集合操作符做相应的操作。集合操作符是一个以@开头特殊的字符串,下面是集合操作的格式插图(来自官方文档):

image

Operator key path format

注意:所有的集合操作,除了@count,其他都需要有右边的keyPath(一般为属性名),目前还不支持自定义集合操作符

集合操作符分为三种:

  • 简单的集合操作 返回NSString、NSNumber、NSDate

  • 对象操作符 返回NSArray

  • 数组或集合操作符 返回NSArray、NSSet

Simple Collection Operators(简单的操作符)

  • @avg 平均值

  • @count 个数

  • @max 最大值

  • @min 最小值

  • @sum 和

    // 平均身高
       float avg = [[students valueForKeyPath:@"@avg.height"] floatValue];
       // 身高总和
       float sum = [[students valueForKeyPath:@"@sum.height"] floatValue];
       // 最大值
       float max = [[students valueForKeyPath:@"@max.height"] floatValue];
       // 最小值
       float min = [[students valueForKeyPath:@"@min.height"] floatValue];
       // 个数
       float count = [[students valueForKeyPath:@"@count"] floatValue];
    

Object Operator (对象操作符)

  • @distinctUnionOfObjects 返回一个由操作符右边的key path所指定的对象属性组成的数组,不对数组去重

  • @unionOfObjects 返回一个由操作符右边的key path所指定的对象属性组成的数组,并对数组去重

NSArray *resultsOne = [studentsOfClassOne valueForKeyPath:@"@unionOfObjects.height"];
NSArray *resultsTwo = [studentsOfClassTwo valueForKeyPath:@"@distinctUnionOfObjects.height"];

Array and Set Operators(数组和集合操作符)

  • @distinctUnionOfArrays/ @unionOfArrays: 返回NSArray,distinct版本会对数组取重

  • @distinctUnionOfSets: 返回一个NSSet对象,因为集合不能包含重复的值,所以它只有distinct操作。

     // 去除相同值的数组
     NSArray *distinctResults = [@[studentsOfClassOne, studentsOfClassTwo] valueForKeyPath:@"@distinctUnionOfArrays.height"];
    

相关文章

网友评论

      本文标题:OC由浅入深系列 之 KVC (二):集合代理对象

      本文链接:https://www.haomeiwen.com/subject/bskbmqtx.html