iOS - 閑聊KVC

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í)行setNamegetName

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)瓶盛,并且將setNamegetName注釋

@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è)置placeholdertextColor時(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];

效果如下圖

屏幕快照 2019-03-22 下午4.23.50.png

但是需要注意

蘋果對一些系統(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ì)重寫settergetter方法,但只在特定的情況下觸發(fā)报辱,通過其他方式不觸發(fā)settergetter与殃,我們可以通過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)容可以參考這里

參考

Key-Value Coding Programming Guide

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市搔耕,隨后出現(xiàn)的幾起案子隙袁,更是在濱河造成了極大的恐慌,老刑警劉巖度迂,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件藤乙,死亡現(xiàn)場離奇詭異,居然都是意外死亡惭墓,警方通過查閱死者的電腦和手機(jī)坛梁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來腊凶,“玉大人划咐,你說我怎么就攤上這事【迹” “怎么了褐缠?”我有些...
    開封第一講書人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵,是天一觀的道長风瘦。 經(jīng)常有香客問我队魏,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任胡桨,我火速辦了婚禮官帘,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘昧谊。我一直安慰自己刽虹,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開白布呢诬。 她就那樣靜靜地躺著涌哲,像睡著了一般。 火紅的嫁衣襯著肌膚如雪尚镰。 梳的紋絲不亂的頭發(fā)上阀圾,一...
    開封第一講書人閱讀 49,764評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音钓猬,去河邊找鬼稍刀。 笑死,一個(gè)胖子當(dāng)著我的面吹牛敞曹,可吹牛的內(nèi)容都是我干的账月。 我是一名探鬼主播,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼澳迫,長吁一口氣:“原來是場噩夢啊……” “哼局齿!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起橄登,我...
    開封第一講書人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬榮一對情侶失蹤抓歼,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后拢锹,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體谣妻,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年卒稳,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蹋半。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡充坑,死狀恐怖减江,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情捻爷,我是刑警寧澤辈灼,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站也榄,受9級(jí)特大地震影響巡莹,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一榕莺、第九天 我趴在偏房一處隱蔽的房頂上張望俐芯。 院中可真熱鬧棵介,春花似錦钉鸯、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至吨述,卻和暖如春岩睁,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背揣云。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來泰國打工捕儒, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人邓夕。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓刘莹,卻偏偏與公主長得像,于是被迫代替她去往敵國和親焚刚。 傳聞我的和親對象是個(gè)殘疾皇子点弯,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對...
    cosWriter閱讀 11,090評(píng)論 1 32
  • 本文參考: KVC官方文檔 KVC原理剖析 iOS KVC詳解 KVC 簡介 KVC全稱是Key Value Co...
    擰發(fā)條鳥xds閱讀 5,284評(píng)論 6 23
  • 原文:iOS 關(guān)于KVC的一些總結(jié) 本文參考: KVC官方文檔 KVC原理剖析 iOS KVC詳解 KVC 簡介 ...
    liyoucheng2014閱讀 935評(píng)論 0 3
  • 關(guān)于鍵值編碼 鍵值編碼(KVC)是一種由NSKeyValueCoding非正式協(xié)議提供的機(jī)制,對象采用該機(jī)制來提供...
    漸z閱讀 913評(píng)論 0 0
  • 大一課堂表現(xiàn)不咋樣…… 大二被主課老師拉去辦公室談話矿咕,老師說了很久抢肛,老師說我為啥沒有反應(yīng)…… 沉默半天我突然想起 ...
    安娜菇?jīng)鰫鄢蕴瘘c(diǎn)閱讀 366評(píng)論 0 0