KVC解析(八) —— KVC几种常见应用

版本记录

版本号 时间
V1.0 2017.09.12

前言

KVC相信大家再熟悉不过了,键值编码,可以解决很多问题,包括视图上的给UITextField占位文字颜色大小进行设置等等,还有很多地方可以用KVC,接下来几篇我们就深度解析一下KVC。总结一下,就是指iOS的开发中,可以允许开发者通过Key名直接访问对象的属性,或者给对象的属性赋值。而不需要调用明确的存取方法。这样就可以在运行时动态地访问和修改对象的属性。而不是在编译时确定,这也是iOS开发中的黑魔法之一。还是老规矩,由面到点,由浅到深,希望对大家有所帮助。感兴趣的可以看我写的另外几篇文章。
1. KVC解析(一) —— 基本了解
2. KVC解析(二) —— 不可不知的赋值深层次原理
3. KVC解析(三) —— 不可不知的取值深层次原理
4. KVC解析(四) —— keyPath的深度解析
5. KVC解析(五) —— KVC几种典型的异常处理
6. KVC解析(六) —— KVC容器类及深层次原理
7. KVC解析(七) —— KVC正确性的验证

取值和赋值

KVC这种基于运行时的编程方式极大地提高了灵活性,简化了代码,甚至实现很多难以想像的功能,KVC也是许多iOS开发黑魔法的基础。在取值和赋值方面的应用,前面几篇讲解别的知识点的时候已经说了很多了,这里就不给大家实例代码了,大家要记住属性和成员变量的调用顺序以及赋值取值的深层次原理。


获取集合对象

这里需要注意的是,取值和赋值不仅可以指单个的属性或者变量值,还可以操作集合对象,比如NSArray或NSSet等,用的方法也就是valueForKey:setValueForKey:


访问和修改私有变量

大家都知道,一个类,只有在.h文件中暴露的属性,别的类才可以引入.h文件的时候并获取其中的属性值,但是如果是私有属性,那么在别的类里面你就不能修改私有属性的值,这个时候KVC就可以了。可以通过KVC为私有属性进行赋值。

下面看代码

1. JJKVCPrivatePropertyVC.h
#import <UIKit/UIKit.h>

@interface JJKVCPrivatePropertyVC : UIViewController

@end
2. JJKVCPrivatePropertyVC.m
#import "JJKVCPrivatePropertyVC.h"

@interface JJKVCPrivatePropertyVC ()

@property (nonatomic, copy) NSString *personName;

@end

@implementation JJKVCPrivatePropertyVC

#pragma mark - Override Base Function

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    NSLog(@"name = %@", self.personName);
}

@end
3. JJKVCPrivateTestVC.h
#import <UIKit/UIKit.h>

@interface JJKVCPrivateTestVC : UIViewController

@end
4. JJKVCPrivateTestVC.m
@interface JJKVCPrivateTestVC ()

@end

@implementation JJKVCPrivateTestVC

#pragma mark - Override Base Function

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    JJKVCPrivatePropertyVC *propertyVC = [[JJKVCPrivatePropertyVC alloc] init];
    [propertyVC setValue:@"小明" forKey:@"personName"];
    [self.navigationController pushViewController:propertyVC animated:YES];
}

@end

下面看输出结果

2017-09-12 23:04:59.475 JJOC[10826:330497] name = 小明

模型和字典的转换

我们可以利用KVC和运行时来对模型和字典进行转换,这个我会在另外一篇文章中进行说明。


修改控件的内部属性

这个我们经常碰到,比如改变UITextFieldplaceHolder的颜色和字体大小,这个我总用到,下面我们就给一个示例。

    //请输入账号
    JJUITextField *accountTextField = [[JJUITextField alloc] init];
    accountTextField.placeholder = @"请输入账号";
    [accountTextField setValue:[UIColor colorWithHexString:@"999999"] forKeyPath:@"_placeholderLabel.textColor"];
    [accountTextField setValue:[UIFont systemFontOfSize:15.0] forKeyPath:@"_placeholderLabel.font"];
    [accountTextField addTarget:self action:@selector(textFieldDidChanged:) forControlEvents:UIControlEventEditingChanged];
    accountTextField.keyboardType = UIKeyboardTypeNumberPad;
    [self addSubview:accountTextField];
    self.accountTextField = accountTextField;

上面给出的示例就是UITextField修改占位颜色和字体的示例代码。目的就是修改账号占位符的颜色和字体大小。


实现多层的消息传递

这里说的多层消息传递,主要指的就是对容器类集合元素应用KVC,对集合元素进行操作时,不是对容器本身进行操作,而是对容器中的每个元素进行操作,返回的是结果也是一个集合元素。

下面我们看示例代码。

#import "JJKVCContainerVC.h"

@interface JJKVCContainerVC ()

@end

@implementation JJKVCContainerVC

#pragma mark - Override Base Function

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    NSArray *arr = @[@"john", @"tom", @"lucy", @"lily"];
    NSArray *captainArr = [arr valueForKey:@"capitalizedString"];
    NSLog(@"captainArr = %@", captainArr);
    
    NSArray *lengthArr = [arr valueForKeyPath:@"capitalizedString.length"];
    NSLog(@"lengthArr = %@",lengthArr);
}

@end

下面看输出结果

2017-09-13 22:17:15.251 JJOC[1866:46208] captainArr = (
    John,
    Tom,
    Lucy,
    Lily
)
2017-09-13 22:17:29.759 JJOC[1866:46208] lengthArr = (
    4,
    3,
    4,
    4
)

从上面代码可以看出来,[arr valueForKey:@"capitalizedString"]方法就是对arr数组的每一个元素进行操作去首字母为大写;[arr valueForKeyPath:@"capitalizedString.length"]方法不仅对每一个元素取大写开头,而且还求长度。


KVC中的函数对集合进行操作

  • 简单运算符

下面还是直接看示例代码

@interface Book : NSObject

@property (nonatomic,copy)  NSString* name;
@property (nonatomic,assign)  CGFloat price;

@end

@implementation Book

@end
Book *book1 = [Book new];
book1.name = @"The Great Gastby";
book1.price = 22;

Book *book2 = [Book new];
book2.name = @"Time History";
book2.price = 12;

Book *book3 = [Book new];
book3.name = @"Wrong Hole";
book3.price = 111;

Book *book4 = [Book new];
book4.name = @"Wrong Hole";
book4.price = 111;

NSArray* arrBooks = @[book1,book2,book3,book4];
NSNumber* sum = [arrBooks valueForKeyPath:@"@sum.price"];
NSLog(@"sum:%f",sum.floatValue);

NSNumber* avg = [arrBooks valueForKeyPath:@"@avg.price"];
NSLog(@"avg:%f",avg.floatValue);

NSNumber* count = [arrBooks valueForKeyPath:@"@count"];
NSLog(@"count:%f",count.floatValue);

NSNumber* min = [arrBooks valueForKeyPath:@"@min.price"];
NSLog(@"min:%f",min.floatValue);

NSNumber* max = [arrBooks valueForKeyPath:@"@max.price"];
NSLog(@"max:%f",max.floatValue);

下面看输出结果

2016-04-20 16:45:54.696 KVCDemo[1484:127089] sum:256.000000
2016-04-20 16:45:54.697 KVCDemo[1484:127089] avg:64.000000
2016-04-20 16:45:54.697 KVCDemo[1484:127089] count:4.000000
2016-04-20 16:45:54.697 KVCDemo[1484:127089] min:12.000000
2016-04-20 16:45:54.697 KVCDemo[1484:127089] max:111.000000
  • 对象运算符

比集合运算符稍微复杂,能以数组的方式返回指定的内容,一共有两种:

@distinctUnionOfObjects
@unionOfObjects

它们的返回值都是NSArray,区别是前者返回的元素都是唯一的,是去重以后的结果;后者返回的元素是全集。

下面我们看一下示例代码。

NSLog(@"distinctUnionOfObjects");
NSArray* arrDistinct = [arrBooks valueForKeyPath:@"@distinctUnionOfObjects.price"];
for (NSNumber *price in arrDistinct) {
    NSLog(@"%f",price.floatValue);
}

NSLog(@"unionOfObjects");
NSArray* arrUnion = [arrBooks valueForKeyPath:@"@unionOfObjects.price"];
for (NSNumber *price in arrUnion) {
    NSLog(@"%f",price.floatValue);
}

下面我们看输出结果

2016-04-20 16:47:34.490 KVCDemo[1522:128840] distinctUnionOfObjects
2016-04-20 16:47:34.490 KVCDemo[1522:128840] 111.000000
2016-04-20 16:47:34.490 KVCDemo[1522:128840] 12.000000
2016-04-20 16:47:34.490 KVCDemo[1522:128840] 22.000000

2016-04-20 16:47:34.490 KVCDemo[1522:128840] unionOfObjects
2016-04-20 16:47:34.490 KVCDemo[1522:128840] 22.000000
2016-04-20 16:47:34.490 KVCDemo[1522:128840] 12.000000
2016-04-20 16:47:34.490 KVCDemo[1522:128840] 111.000000
2016-04-20 16:47:34.490 KVCDemo[1522:128840] 111.000000
  • Array和Set操作符

说的是集合中包含集合的情况,我们执行了如下的一段代码:

@distinctUnionOfArrays
@unionOfArrays
@distinctUnionOfSets

(1) @distinctUnionOfArrays:该操作会返回一个数组,这个数组包含不同的对象,不同的对象是在从关键路径到操作器右边的被指定的属性里。
(2) @unionOfArrays 该操作会返回一个数组,这个数组包含的对象是在从关键路径到操作器右边的被指定的属性里和@distinctUnionOfArrays不一样,重复的对象不会被移除。
(3) @distinctUnionOfSets@distinctUnionOfArrays类似。因为Set本身就不支持重复。

KVO

KVO是基于KVC实现的,后面我会详细的说一下KVO,到时候会分开几篇说一下这一点。

后记

未完,待续~~~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,294评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,780评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,001评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,593评论 1 289
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,687评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,679评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,667评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,426评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,872评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,180评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,346评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,019评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,658评论 3 323
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,268评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,495评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,275评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,207评论 2 352

推荐阅读更多精彩内容