這兩天晚上在學習騰訊公開課的視頻,其中在1月18號的內容是KVC的底層實現??赐旰蠛唵斡浺幌聦W習筆記。
1、[obj valueForKey:key]的搜索路徑
第一步,首先會搜索getter方法(3個方法)。優先級 -getKey > Key > isKey。
第二步,若找不到找getter 方法 ,則尋找+(BOOL)accessInstanceVariablesDirectly;方法。如果類方法返回NO,跳過第三步。
第三步,尋找相關的成員變量(4個)。優先級_key > _isKey > key > isKey。
第四步,還沒找到的話,查找countOfKey、enumeratorOfKey、memberOfKey格式的方法。如果這三個方法都找到,那么就返回一個可以響應NSSet所有方法的代理集合。
如果以上方法都拿不到,調用valueForUndefinedKey。
2、[obj setValueForKey:key]的搜索路徑
第一步,搜索setter相關方法(2個方法)。優先級setKey > setIsKey。
第二步,尋找+(BOOL)accessInstanceVariablesDirectly;方法如果返回NO,跳過第三步
第三步,尋找相關的成員變量(4個)。優先級_key > _isKey > key > isKey。
如果沒有找到成員變量,調用setValue:forUnderfinedKey:
3、KVC防崩潰處理
分別實現 valueForUndefinedKey 和 setValue:forUnderfinedKey: 以及setNilValueForKey方法。
4、通過KeyPath來設值
在開發過程中,一個類的成員變量有可能是其他的自定義類,你可以先用KVC獲取出來再該屬性,然后再次用KVC來獲取這個自定義類的屬性,但這樣是比較繁瑣的,對此,KVC提供了一個解決方案,那就是鍵路徑KeyPath
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;?
//第一步就是分離key,用小數點.來分割key,然后再像普通key一樣按照先前介紹的順序搜索下去。
5、KVC容器方法
- (NSMutableArray*)mutableArrayValueForKey:(NSString*)key;
//這是集合操作的API,里面還有一系列這樣的API,如果屬性是一個NSMutableArray,那么可以用這個方法來返回。
6、集合運算符
簡單集合運算符:@avg、@sum、@max、@min、@count (只能用在集合對象中,對象屬性必須為數字類型)
NSInteger count = [[perArray valueForKeyPath:@"@count.age"] integerValue];
7、對象操作符
@unionOfObjects:返回指定屬性的值的數組,不去重
NSArray *nameArray = [perArray valueForKeyPath:@"@unionOfObjects.name"];
@distinctUnionOfObjects:返回指定屬性去重后的值的數組
NSArray *nameArray2 = [perArray valueForKeyPath:@"@distinctUnionOfObjects.name"];
8、數組 / 集體操作符
跟對象操作符很相似,只不過是在NSArray和NSSet所組成的集合中工作的。
// 數組 / 集體操作符 : 對由NSArray和NSSet所組成的集合操作
// unionOfArrays:返回一個數組,值由各個子數組的元素組成,不去重
// distinctUnionOfArrays:返回一個數組,值由各個子數組的元素組成,去重
// distinctUnionOfSets:和distinctUnionOfArrays差不多, 只是它期望的是一個包含著NSSet對象的NSSet,并且會返回一個NSSet對象。因為集合不能包含重復的值,所以它只有distinct操作。
Person *P1 = [[Person alloc] initWithName:@"PP1"andAge:10];
Person *P2 = [[Person alloc] initWithName:@"PP1"andAge:20];
Person *P3 = [[Person alloc] initWithName:@"PP2"andAge:30];
Person *P4 = [[Person alloc] initWithName:@"PP3"andAge:40];
Person *P5 = [[Person alloc] initWithName:@"PP3"andAge:50];
NSArray *perArray2 = @[P1, P2, P3, P4, P5];
NSArray *arr1 = [@[perArray,perArray2] valueForKeyPath:@"@unionOfArrays.name"];
NSArray *arr2 = [@[perArray,perArray2] valueForKeyPath:@"@distinctUnionOfArrays.name"];