KVC
KVC(Key-Value-Coding)
是Cocoa框架為我們提供的非常強(qiáng)大的工具泣矛,簡譯為鍵值編碼疲眷。iOS的開發(fā)中,可以允許開發(fā)者通過Key
名直接訪問對象的屬性您朽,或者給對象的屬性賦值狂丝。而不需要調(diào)用明確的存取方法。這樣就可以在運(yùn)行時(shí)動(dòng)態(tài)地訪問和修改對象的屬性哗总,而不是在編譯時(shí)確定几颜,這也是iOS開發(fā)中的黑魔法之一。KVC
依賴于RunTime
讯屈,在Objective-C
的動(dòng)態(tài)性方面發(fā)揮了重要作用蛋哭。很多高級(jí)的iOS開發(fā)技巧都是基于KVC實(shí)現(xiàn)的。
KVC
的主要功能是直接通過變量名稱字符串來訪問成員變量涮母,不管是私有的還是公有的谆趾,這也就是為什么對于Objective-C
來說,沒有真正的私有變量叛本。因?yàn)橐皇强梢岳?code>RunTime直接獲取所有成員變量沪蓬,二是通過KVC
對成員變量進(jìn)行訪問讀寫。
基本內(nèi)容
無論是Swift
還是Objective-C
来候,KVC
的定義都是對NSObject
的擴(kuò)展來實(shí)現(xiàn)的(Objective-C
中有個(gè)顯式的NSKeyValueCoding
類別名跷叉,而Swift
沒有,也不需要)。所以對于所有直接或者間接繼承了NSObject
的類型云挟,也就是幾乎所有的Objective-C
對象都能使用KVC
(一些純Swift類和結(jié)構(gòu)體是不支持KVC的)峡眶,下面是KVC
重要的四個(gè)方法
- (id)valueForKey:(NSString *)key; // 直接通過Key來取值
- (void)setValue:(nullable id)value forKey:(NSString *)key; // 通過Key來設(shè)值
- (nullable id)valueForKeyPath:(NSString *)keyPath; // 通過KeyPath來取值
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath; // 通過KeyPath來設(shè)值
KVC中key的查找順序
設(shè)置值的查找順序
1、程序優(yōu)先調(diào)用
set<Key>:
屬性值方法植锉,代碼通過setter
方法完成設(shè)置辫樱。注意,這里的<key>
是指成員變量名2俊庇、如果沒有找到
set<Key>:
方法狮暑,KVC機(jī)制會(huì)檢查+ (BOOL)accessInstanceVariablesDirectly
方法有沒有返回YES
,默認(rèn)該方法會(huì)返回YES
辉饱,如果你重寫了該方法讓其返回NO
的話搬男,那么在這一步KVC會(huì)執(zhí)行setValue:forUndefinedKey:
方法。在方法返回YES
的情況下彭沼,緊接著就會(huì)查找_<key>
缔逛,如果沒有_<key>
成員變量,KVC機(jī)制會(huì)搜索_is<Key>
的成員變量姓惑。3褐奴、如果該類既沒有
set<Key>
:方法,也沒有_<key>
和_is<Key>
成員變量于毙,KVC
機(jī)制再會(huì)繼續(xù)搜索<key>
和is<Key>
的成員變量敦冬。再給它們賦值。4唯沮、如果上面列出的方法或者成員變量都不存在脖旱,系統(tǒng)將會(huì)執(zhí)行該對象的
setValue:forUndefinedKey:
方法,默認(rèn)是拋出異常介蛉,如果實(shí)現(xiàn)了該方法萌庆,那么不會(huì)拋出異常。
具體例子分析
創(chuàng)建一個(gè)Person類币旧,實(shí)現(xiàn)如下
@interface Person : NSObject
@end
@implementation Person
{
NSString *setName;
NSString *isName;
NSString *_name;
NSString *_isName;
NSString *name;
}
- (void)setName:(NSString *)name {
setName = name;
NSLog(@"setName: %@", name);
}
- (NSString *)getName {
NSLog(@"getName");
return setName;
}
+ (BOOL)accessInstanceVariablesDirectly {
return NO;
}
- (void)setValue:(id)value forUndefinedKey:(NSString *)key {
NSLog(@"setValueForUndefinedKey: %@", key);
}
- (id)valueForUndefinedKey:(NSString *)key {
NSLog(@"valueForUndefinedKey: %@", key);
return nil;
}
@end
測試部分
- (void)viewDidLoad {
[super viewDidLoad];
Person *person = [[Person alloc]init];
[person setValue:@"newName" forKey:@"name"];
NSString *name = [person valueForKey:@"name"];
NSLog(@"name: %@", name);
}
1践险、將accessInstanceVariablesDirectly
注釋掉,運(yùn)行程序佳恬,將執(zhí)行setName
和getName
setName: newName
getName
name: newName
也就是說先調(diào)用set<Key>:
方法
2捏境、接下來將setName
方法注釋掉,并且修改getName
方法毁葱,將返回值修改為_name
//- (void)setName:(NSString *)name {
// setName = name;
// NSLog(@"setName: %@", name);
//}
- (NSString *)getName {
NSLog(@"getName:%@", _name);
return _name;
}
運(yùn)行程序垫言,結(jié)果如下
getName:newName
name: newName
也就是滿足了第二步,如果沒有找到set<Key>:
方法倾剿,就會(huì)查找_<key>
為其賦值
3筷频、注釋掉_name
蚌成,并修改getName
方法,返回_isName
@implementation Person
{
NSString *setName;
NSString *isName;
// NSString *_name;
NSString *_isName;
NSString *name;
}
- (NSString *)getName {
NSLog(@"getName:%@", _isName);
return _isName;
}
運(yùn)行程序凛捏,結(jié)果如下
getName:newName
name: newName
后面2步就不再驗(yàn)證担忧,有興趣可以自己嘗試。
接下來驗(yàn)證accessInstanceVariablesDirectly
屬性坯癣,代碼回復(fù)到最初狀態(tài)瓶盛,并且將setName
和getName
注釋
@implementation Person
{
NSString *setName;
NSString *isName;
NSString *_name;
NSString *_isName;
NSString *name;
}
//- (void)setName:(NSString *)name {
// setName = name;
// NSLog(@"setName: %@", name);
//}
//
//- (NSString *)getName {
// NSLog(@"getName");
// return setName;
//}
+ (BOOL)accessInstanceVariablesDirectly {
return NO;
}
- (void)setValue:(id)value forUndefinedKey:(NSString *)key {
NSLog(@"setValueForUndefinedKey: %@", key);
}
- (id)valueForUndefinedKey:(NSString *)key {
NSLog(@"valueForUndefinedKey: %@", key);
return nil;
}
@end
依然運(yùn)行程序,結(jié)果如下
setValueForUndefinedKey: name
valueForUndefinedKey: name
name: (null)
說明再找不到setName:
方法后示罗,不再去找name
系列成員變量惩猫,而是直接調(diào)用setValue:forUndefinedKey:
方法
獲取值的查找順序
1、首先按
get<Key>蚜点,<key>轧房,is<Key>
的順序查找getter
方法,找到直接調(diào)用绍绘。如果是BOOL奶镶、int
等內(nèi)建值類型,會(huì)做NSNumber
的轉(zhuǎn)換陪拘。2厂镇、如果上面的
getter
沒有找到,KVC
則會(huì)查找countOf<Key>,objectIn<Key>AtIndex
或<Key>AtIndexes
格式的方法藻丢。如果countOf<Key>
方法和另外兩個(gè)方法中的一個(gè)被找到剪撬,那么就會(huì)返回一個(gè)可以響應(yīng)NSArray
所有方法的代理集合(它是NSKeyValueArray
摄乒,是NSArray
的子類)悠反,調(diào)用這個(gè)代理集合的方法,或者說給這個(gè)代理集合發(fā)送屬于NSArray的方法馍佑,就會(huì)以countOf<Key>,objectIn<Key>AtIndex
或<Key>AtIndexes
這幾個(gè)方法組合的形式調(diào)用斋否。還有一個(gè)可選的get<Key>:range:
方法。所以你想重新定義KVC
的一些功能拭荤,你可以添加這些方法茵臭,需要注意的是你的方法名要符合KVC的標(biāo)準(zhǔn)命名方法,包括方法簽名舅世。3旦委、還沒找到,查找
countOf<Key>雏亚、enumeratorOf<Key>缨硝、memberOf<Key>
格式的方法。如果這三個(gè)方法都找到罢低,那么就返回一個(gè)可以響應(yīng)NSSet
所有方法的代理集合查辩。4胖笛、還是沒找到,如果類方法
accessInstanceVariablesDirectly
返回YES
宜岛。那么按_<key>长踊,_is<Key>,<key>萍倡,is<key>
的順序搜索成員名身弊。5、再?zèng)]找到列敲,調(diào)用
valueForUndefinedKey
佑刷。
在KVC中使用keyPath
開發(fā)過程中,一個(gè)類的成員變量有可能是自定義類或其他的復(fù)雜數(shù)據(jù)類型酿炸,你可以先用KVC獲取該屬性瘫絮,然后再次用KVC來獲取這個(gè)自定義類的屬性,但這樣是比較繁瑣的填硕,對此麦萤,KVC提供了一個(gè)解決方案,那就是鍵路徑keyPath
- (nullable id)valueForKeyPath:(NSString *)keyPath; // 通過KeyPath來取值
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath; // 通過KeyPath來設(shè)值
具體例子
@interface Account : NSObject
@property (nonatomic, copy) NSString *password;
@end
@implementation Account
@end
@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSNumber *age;
@property (nonatomic, copy) NSString *address;
@property (nonatomic, strong) Account *count;
@end
Example
Person *person = [[Person alloc]init];
Account *account = [[Account alloc] init];
account.password = @"xxxx";
person.account = account;
NSString *password1 = [person valueForKeyPath:@"account.password"];
[person setValue:@"yyyy" forKeyPath:@"account.password"];
NSString *password2 = [person valueForKeyPath:@"account.password"];
NSLog(@"password1 = %@, password2 = %@", password1, password2);
// password1 = xxxx, password2 = yyyy
對象關(guān)系映射
ORM(Object Relational Mapping扁眯,對象關(guān)系映射)
壮莹,說白了就是將JSON
轉(zhuǎn)換為對象。在iOS開發(fā)最初的一段時(shí)間姻檀,還沒有特別好的第三方Model
解析庫命满,那時(shí)候基本上是使用NSKeyValueCoding
提供的方法
Example
// Person.h
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSNumber *age;
@property (nonatomic, copy) NSString *address;
@end
NS_ASSUME_NONNULL_END
// Person.m
#import "Person.h"
@implementation Person
- (void)setValue:(id)value forUndefinedKey:(NSString *)key {
NSLog(@"UndefinedKey: %@", key);
}
@end
// ViewController.m
#import "ViewController.h"
#import "Person.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSDictionary *dic = @{@"name": @"xiao",
@"age": @22,
@"address": @"China",
@"phone": @"186xxxxxxxx"
};
Person *person = [[Person alloc]init];
[person setValuesForKeysWithDictionary:dic];
}
@end
對私有屬性的訪問
在我們使用一些系統(tǒng)控件時(shí),對一些內(nèi)部屬性系統(tǒng)往往并沒有暴露給我們绣版,需要我們使用KVC
進(jìn)行訪問胶台。
例如,在使用UITextField
時(shí)杂抽,對于設(shè)置placeholder
的textColor
時(shí)只能通過attributedPlaceholder
這樣的NSAttributedString
來設(shè)置诈唬,并且每次更改都需要這樣設(shè)置一遍,有些麻煩缩麸。這里可以通過KVC
來獲取_placeholderLabel
并對其賦值铸磅,修改顏色
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(50, 100, 300, 44)];
textField.borderStyle = UITextBorderStyleRoundedRect;
textField.placeholder = @"please input something....";
UILabel *placeLabel = [textField valueForKey:@"_placeholderLabel"];
placeLabel.textColor = [UIColor redColor];
[self.view addSubview:textField];
效果如下圖
但是需要注意:
蘋果對一些系統(tǒng)控件的實(shí)現(xiàn)過程中,很多子控件使用了懶加載杭朱,即用到時(shí)才會(huì)去創(chuàng)建實(shí)例阅仔,所以使用KVC
進(jìn)行訪問時(shí),需要注意訪問的時(shí)機(jī)弧械。
例如上面八酒,應(yīng)該在placeholder
設(shè)置值之后才訪問,否則_placeholderLabel
獲取為nil,textColor
設(shè)置無效梦谜。
另外一個(gè)需要注意的地方:雖然采用KVC
訪問一些私有成員變量不屬于使用私有API丘跌,上線時(shí)不太會(huì)因此被拒絕袭景,但是私有的成員變量可能會(huì)隨著iOS版本的不同而有所變化。
所以使用KVC
訪問私有變量時(shí)需要謹(jǐn)慎闭树。
控制是否觸發(fā)setter耸棒、getter方法
有些時(shí)候?yàn)榱吮O(jiān)控某個(gè)屬性的值訪問情況會(huì)重寫setter
或getter
方法,但只在特定的情況下觸發(fā)报辱,通過其他方式不觸發(fā)setter
或getter
与殃,我們可以通過KVC
來做。例如:上面的Person
類碍现,重寫name
屬性的setter
方法幅疼,如下:
// Person.m
- (void)setName:(NSString *)name {
_name = name;
NSLog(@"setName: %@", name);
}
// ViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
NSDictionary *dic = @{@"name": @"xiao",
@"age": @22,
@"address": @"China",
@"phone": @"186xxxxxxxx"
};
Person *person = [[Person alloc]init];
[person setValuesForKeysWithDictionary:dic];
[person setValue:@"zhangsan" forKey:@"_name"];
}
運(yùn)行輸出
undefinedKey: phone
setName: xiao
只有在 [person setValuesForKeysWithDictionary:dic];
時(shí)觸發(fā)過一次setName:
的方法,而通過KVC
給_name
賦值并不會(huì)觸發(fā)昼接,如果也想觸發(fā)爽篷,可以將“_name”
改成“name”
來實(shí)現(xiàn)。
[person setValue:@"zhangsan" forKey:@"name"];
這樣運(yùn)行輸出
undefinedKey: phone
setName: xiao
setName: zhangsan
可以根據(jù)實(shí)際需求慢睡,選擇使用KVC
的方法逐工,出現(xiàn)上面的情況是因?yàn)?code>KVC的查找成員變量的機(jī)制。
查找成員變量的機(jī)制
如果一個(gè)實(shí)例對象用KVC
來訪問其成員變量漂辐,則會(huì)按照以下的順序來進(jìn)行查找泪喊,例如:我們調(diào)用的方法是:
[person setValue:@"aa" forKey:@"name"];
1、訪問setName
方法
2髓涯、訪問_name
成員變量
3袒啼、訪問_isName
成員變量
4、訪問name
成員變量
5纬纪、訪問isName
成員變量
以上就是KVC
查找的過程蚓再,只有在某一步找到才會(huì)不繼續(xù)向下查找,否則會(huì)按照上面的順序逐個(gè)查找育八,如果到最后一個(gè)也找不到对途,那就會(huì)調(diào)用)setValue:forUndefinedKey:
方法。
值得注意的是髓棋,KVC
的協(xié)議NSKeyValueCoding
中的accessInstanceVariablesDirectly
屬性:
@property (class, readonly) BOOL accessInstanceVariablesDirectly;
該屬性默認(rèn)為YES
,如果重寫返回NO
惶洲,則下面這些方法都將不起作用
-valueForKey:, -setValue:forKey:, -mutableArrayValueForKey:,
-storedValueForKey:, -takeStoredValue:forKey:, and -takeValue:forKey:
也就是相當(dāng)于禁止KVC的方法按声。但是我們在之前使用setValuesForKeysWithDictionary:
方法仍然可以使用。
KVC進(jìn)階用法
KVC
的使用可不僅僅是訪問成員變量這么簡單恬吕,蘋果為KVC提供了一些高級(jí)的用法签则,方便開發(fā)者在代碼中的使用
1、keyPath訪問
對于keyPath
訪問很多人應(yīng)該不陌生铐料,在一些ORM
庫中經(jīng)常會(huì)指向通過keyPath
來映射賦值渐裂。
舉個(gè)例子:回到剛才的textFiled
的場景豺旬,我們知道有一個(gè)“_placeholderLabel”
成員變量,它是一個(gè)UILabel
的實(shí)例柒凉,我們獲取到該UILabel
族阅,并對其進(jìn)行textColor
屬性賦值,達(dá)到了想要的效果膝捞。但實(shí)際上可以一步完成上面的操作
UITextField *textField = [[UITextField alloc]initWithFrame:CGRectMake(100, 100, 200, 50)];
textField.placeholder = @"placeholder";
[textField setValue:[UIColor redColor] forKeyPath:@"_placeholderLabel.textColor"];
[self.view addSubview:textField];
2坦刀、集合類型的訪問
集合類型包括數(shù)組、字典和集合蔬咬,其中鲤遥,集合還分為有序和無序。對于我們的Person
類林艘,現(xiàn)在需要一個(gè)屬性friends
:
@property(nonatomic, strong) NSMutableArray *friends;
然后在Person.m
文件中會(huì)有提示下面等一系列方法
-(id)objectInFriendsAtIndex:(NSUInteger)index
-(NSArray *)friendsAtIndexes:(NSIndexSet *)indexes
-(NSUInteger)countOfFriends
這是KVC
幫我們針對friends
屬性添加的一系列方法中的幾個(gè)盖奈,表示對friends
屬性支持KVC
集合類型,目的是方便我們使用KVC
時(shí)對其進(jìn)行便捷式訪問狐援。那么什么是便捷式訪問呢卜朗?
假設(shè)一下,如果我們要通過KVC
獲取到Person
對象的friends
屬性咕村,并添加一個(gè)friend
场钉,如果不使用KVC
集合類型訪問,可能需要這樣寫:
//方式1
NSMutableArray *friends = [person valueForKey:@"friends"];
[friends addObject:[Person new]];
// 當(dāng)然也可以使用該方法
[person.friends addObject:[Person new]];
通過KVC
方式懈涛,我們可以簡化方式1的操作
[[person mutableArrayValueForKey:@"friends"] addObject:[Person new]];
除了簡化代碼這一點(diǎn)逛万,實(shí)際上這種KVC
集合類型還有一個(gè)好處,就是可以對于不可變的集合類型提供安全的可變訪問批钠。
上面部分宇植,我們的friends
屬性是可變數(shù)組,如果改成不可變數(shù)組NSArray
埋心,那么再對其進(jìn)行添加對象指郁,使用上面的兩種方法就會(huì)不一樣了,前者會(huì)直接crash
拷呆,而后者則會(huì)安全訪問闲坎,即使是不可變數(shù)組也可以增加數(shù)組元素。
但我們知道對于NSArray
是不可變的茬斧,這在創(chuàng)建Person
實(shí)例的時(shí)候就已經(jīng)確定好了腰懂,對其添加元素,并不是不可變數(shù)組可以添加元素项秉,而是在用KVC
進(jìn)行集合類型訪問時(shí)绣溜,如果是不可變數(shù)組,在添加元素時(shí)會(huì)重新創(chuàng)建一個(gè)不可變數(shù)組對象娄蔼,然后將friends
屬性指向新創(chuàng)建的不可變數(shù)組怖喻。
雖然使用這種方式不會(huì)引起奔潰底哗,但是在創(chuàng)建Person
類時(shí),既然將friends
屬性設(shè)置為不可變數(shù)組锚沸,那么就應(yīng)該避免再向其添加對象跋选,因?yàn)檫@與最初的邏輯相左。
3咒吐、KVC驗(yàn)證
使用KVC
也是有風(fēng)險(xiǎn)的野建,因?yàn)橥ㄟ^字符串去訪問實(shí)例變量,雖然KVC提供類復(fù)雜的查找邏輯來幫助找到對應(yīng)的成員變量恬叹,但是仍然會(huì)發(fā)生找不到的情況候生。
例如:我們使用-setValue:forKey
來對對象進(jìn)行賦值訪問,當(dāng)-setValue:forUndefinedKey
沒有實(shí)現(xiàn)绽昼,而且如果key
不存在唯鸭,將會(huì)導(dǎo)致奔潰。
[person setValue:@"123" forKey:@"key"];
如果想避免奔潰硅确,實(shí)現(xiàn)-setValue:forUndefinedKey
目溉,打印不存在的key
,或者使用try-catch
菱农,如下使用try-catch
捕獲異常缭付,得到相關(guān)信息
NSDictionary *dic = @{@"name": @"xiao",
@"age": @22,
@"address": @"China"
};
Person *person = [[Person alloc]init];
[person setValuesForKeysWithDictionary:dic];
@try {
[person setValue:@"123" forKey:@"thought"];
} @catch (NSException *exception) {
NSLog(@" %@", exception.userInfo);
} @finally {
}
打印如下:
{
NSTargetObjectUserInfoKey = "<Person: 0x600000ed3840>";
NSUnknownUserInfoKey = thought;
}
NSUnknownUserInfoKey
所對應(yīng)的值就是不存在的key
除了上面的方法,KVC
還提供了一種值驗(yàn)證的方法
- (BOOL)validateValue:(inout id _Nullable __autoreleasing *)ioValue
forKey:(NSString *)inKey
error:(out NSError * _Nullable __autoreleasing *)outError
該方法是驗(yàn)證值是否符合key
所對應(yīng)的類型循未,或者說值類型是否正確陷猫。方法中的ioValue
參數(shù)是要賦值二級(jí)指針類型。如果不是我們想要的值的妖,則可以直接改變ioValue
的指向绣檬,也就是重新指向一個(gè)正確的值。
例如:我們現(xiàn)在驗(yàn)證Person
實(shí)例的字符串屬性name
嫂粟,因此調(diào)用驗(yàn)證方法來判斷
UIColor *color = [UIColor yellowColor];
NSError *error = nil;
BOOL isOK = [person validateValue:&color forKeyPath:@"name" error:&error];
name
屬性需要接受字符串類型的值娇未,很顯然我們傳一個(gè)color是錯(cuò)誤的,然而通過運(yùn)行發(fā)現(xiàn)驗(yàn)證的返回值是YES
星虹,表示驗(yàn)證通過零抬,這明顯不合理。
根據(jù)官方文檔描述搁凸,對于屬性的驗(yàn)證分為是否必需媚值,默認(rèn)為不必需,如果是不必需护糖,則會(huì)直接返回YES
,不會(huì)對其進(jìn)行驗(yàn)證嚼松,而如果需要驗(yàn)證嫡良,則需要在Person.m
中實(shí)現(xiàn)如下方法
-(BOOL)validateName:(id *)ioValue error:(NSError **)error {
if ([*ioValue isKindOfClass:NSString.class]) {
return YES;
}
return NO;
}
現(xiàn)在再去驗(yàn)證锰扶,會(huì)發(fā)現(xiàn)返回NO
,符合我們的預(yù)期寝受。
4坷牛、函數(shù)操作
同樣還是對于一些集合類型的數(shù)據(jù),我們希望可以利用共同性去做一些快捷的操作很澄,例如求平均值和求和等京闰,不需要再去for循環(huán)或者枚舉。
例如:有一個(gè)Person
類型的數(shù)組甩苛,想求所有person的age之和
NSDictionary *dic1 = @{@"name": @"1",
@"age": @22
};
NSDictionary *dic2 = @{@"name": @"2",
@"age": @21
};
NSDictionary *dic3 = @{@"name": @"3",
@"age": @23
};
Person *person1 = [[Person alloc]init];
Person *person2 = [[Person alloc]init];
Person *person3 = [[Person alloc]init];
[person1 setValuesForKeysWithDictionary:dic1];
[person2 setValuesForKeysWithDictionary:dic2];
[person3 setValuesForKeysWithDictionary:dic3];
NSArray *persons = @[person1, person2, person3];
NSNumber *sumAge = [persons valueForKeyPath:@"@sum.age"];
NSLog(@"sumAge: %@", sumAge); // 66
上面獲取的就是所有人的age之和蹂楣,不用for循環(huán),直接使用KVC
實(shí)現(xiàn)讯蒲。
注意:使用的是KeyPath
痊土,并且sum
前面加一個(gè)@
表示是數(shù)組特有的鍵.
除此之外,還可以求出數(shù)組的平均值墨林、最大值赁酝、最小值
NSNumber *count = [persons valueForKeyPath:@"@count"];
NSLog(@"count: %@", count); // 3
NSNumber *ageAve = [persons valueForKeyPath:@"@avg.age"];
NSLog(@"avg: %@", ageAve); // 22
NSNumber *maxAge = [persons valueForKeyPath:@"@max.age"];
NSLog(@"max: %@", maxAge); // 23
NSNumber *minAge = [persons valueForKeyPath:@"@min.age"];
NSLog(@"min: %@", minAge); // 21
在NSKeyValueCoding.h文件中,定義了一系列的NSKeyValueOperator
,而這些Operator都是為數(shù)組類型準(zhǔn)備的旭等。
更多詳細(xì)內(nèi)容可以參考這里