IOS SDK详解之KVC

原创Blog,转载请注明出处
blog.csdn.net/hello_hwc


前言:本文的架构
KVC的定义
KVC的几个场景

希望,通过本文让不了解KVC的同学入门,KVC在IOS开发中是个比较重要的概念,也是理解KVO的基础。


一 KVC的定义
KVC的全称是key-value coding,通过key-value的方式来访问属性。在很多地方,KVC是非常方便的。
属性

@property (strong,nonatomic) NSString * message;

赋值

 [self setValue:@"blog.csdn.net/hello_hwc" forKey:@"message"];

取值

 NSString * message =   [self valueForKey:@"message"];

除了对象可以用KVC,对标量也可以用KVC,因为Foundation对标量的KVC进行了内部转换。
例如

@property (nonatomic) int number;
[self setValue:@(10) forKey:@"number"];
NSNumber *  num = [self valueForKey:@"number"];

以上讲的都是valueForKey,KVC也支持valueForKeyPath,这里的path是字符串路径,用点来隔开,逐层深入。
例如

所以,valueForKeyPath对于复杂的集合类处理以及对于复杂的属性访问很简便。
例如

    NSArray * array = @[@{@"key":@{@"1":@"2"},@"key2":@"value2"},
                        @{@"key":@{@"1":@"3"},@"key2":@"value2"},
                        @{@"key":@{@"1":@"4"},@"key2":@"value2"}
                        ];
    NSLog(@"%@",[array valueForKeyPath:@"key.1"]);

简单讲解下这个过程
对每个对象进行valueForKey:@”key”,然后对返回的数组在进行
valueForKey@“1“


二 KVC的典型使用场景

2.1 Model与View同步的中间件。
我写了个简单的使用Demo
效果如图
技术分享
每次点Create,会生成100以内随机数,然后几个label分别展示相应的统计。

这里的核心是model和view的同步。

采用如下代码来实现

-(NSArray *)stringKeys{
    return @[@"min",@"max",@"avg"];
}

-(NSString *)aggregationKeypath:(NSString *)key{
    return [NSString stringWithFormat:@"@%@.self",key];
}

-(UILabel *)labelForKey:(NSString *)key{
    return [self valueForKey:key];
}

-(void)updateAggregationLabels{ 
  for (NSString * key in self.stringKeys) {
        UILabel * label = [self labelForKey:key];
        NSNumber * aggregation = [self.numArray valueForKeyPath:[self aggregationKeypath:key]];
        label.text = [NSString stringWithFormat:@"%@: %.1f",key,aggregation.doubleValue];
    }
}

- (IBAction)createTenRandomNumbers:(id)sender {
    [self.numArray removeAllObjects];
    NSString * string = @"";
    for (int i = 0; i < 10; i++) {
        int num = arc4random()%100;
        [self.numArray addObject:@(num)];
        string = [NSString stringWithFormat:@"%@ %d",string,num];
    }
    self.numbers.text = string;
    [self updateAggregationLabels];
}

这里,用KVC的方式访问属性。

有些同学不禁会问,我干嘛不直接在这个target-action中直接响应。这么写主要是为了方便以后维护。例如,假如我要新加上一个label叫做count,以上的代码中,我只需要修改一个函数,就是为
-(NSArray *)stringKeys{
    return @[@"min",@"max",@"avg"];
}
这个数组添加一个新的key。一个简单的例子,抛砖引玉,主要是尽量解耦合的思想,这个很重要。

2.2 KVC集成了几个集合的运算符,用起来非常方便,代码执行效率也很高。
集合运算符的表达形式就是在keyPath中的双引号里面出现@
例如

@"@min.count"

2.2.1集合运算符分为几种:

  • 简单集合运算符:返回string,number,date
  • 对象运算符:返回一个数组
  • 数组和集合运算符:返回一个数组或者集合

基本集合运算符分为几种

@count 
@max
@min
@avg
@sum

为了更好的讲解,写一个model类

@interface User : NSObject
@property (strong,nonatomic)NSString * name;
@property (nonatomic) NSUInteger accessTimes;
-(instancetype)initWithName:(NSString *)name Count:(NSUInteger) times;
@end

然后,进行举例
对一个user的数组进行初始化

-(NSMutableArray *)users{
    if (!(_users)) {
        _users = [[NSMutableArray alloc] init];
        [_users addObject:[[User alloc] initWithName:@"jack" Count:100]];
        [_users addObject:[[User alloc] initWithName:@"lucy" Count:150]];
        [_users addObject:[[User alloc] initWithName:@"tom" Count:80]];
        [_users addObject:[[User alloc] initWithName:@"lily" Count:80]];

    }
    return _users;
}

然后,用KVC的形式进行访问数据

NSArray * names = [self.users valueForKeyPath:@"name"];
    NSArray * counts = [self.users valueForKeyPath:@"accessTimes"];
    NSNumber * avg = [self.users valueForKeyPath:@"@avg.accessTimes"];

2.2.2 对象操作符

@unionOfObjects     返回keyPath的结果,重复信息不过滤
@distinucUnionOfObjects  重复信息过滤

例如

 NSArray * time1 = [self.users valueForKeyPath:@"@unionOfObjects.accessTimes"];
    NSArray * time2 = [self.users valueForKeyPath:@"@distinctUnionOfObjects.accessTimes"];
    NSLog(@"%@",time1.description);
    NSLog(@"%@",time2.description);

输出

2015-02-12 21:12:38.513 KvcKvoDemo[501:11415] (
100,
150,
80,
80
)
2015-02-12 21:12:38.514 KvcKvoDemo[501:11415] (
150,
80,
100
)


2.3 KVC的一些错误处理
标量不能为nil
例如

@property (nonatomic) int number;

然后

[self setValue:nil forKey:@"number"];

如果不进行错误处理,程序就会崩溃

用这个函数进行想要的错误处理
-(void)setValue:(id)value forUndefinedKey:(NSString *)key{
    NSLog(@"undfined key");
}

未识别的key处理

 [self setValue:nil forKey:@"dsag"];
 [self valueForKey:@"123124"];

胡乱输入的两个key,如果不进行错误处理,程序就会崩溃掉。
用这两个函数来处理未识别的key,至于怎么处理,因情况而定。

-(void)setValue:(id)value forUndefinedKey:(NSString *)key{
    NSLog(@"set undfined key");
}
-(id)valueForUndefinedKey:(NSString *)key{
    NSLog(@"get undfined key");
    return nil;
}

当然,用消息转发技术,在错误处理的下一步来处理错误也行。这其中又涉及到IOS runtime的内容,牵涉过多,不在本文的讨论范畴了。不过,不要让错误传递太久,及时处理掉,总没错。


郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。