KVC的全称为key value coding,它是一种使用字符串间接更改对象属性的方法。

假设有一个Person类和一个Student类,其中Person类有age、name两个属性,Student多一个no(学号)属性。

1.valueForKey: 方法通过传入一个键值返回一个id对象,KVC具有自动包装功能,注意如果是基本类型会返回被包装的对象,需要使用XxxValue方法解包,例如:

NSLog(@"%d",[[s valueForKey:@"age"] intValue]);

虽然age属性为int,但是在这个方法下返回的为NSNumber,应该解包再使用。

2.setValue: forKey: 可以通过key设置Value,对于基本类型应该用NSNumber或者NSValue进行包装(也可以通过@(...)快速包装)。

[s setValue:@18 forKey:@"age"];

[s setValue:[NSNumber numberWithInt:18] forKey:@"age"];

Tip:上面两个方法是非常智能的,会先去寻找getter方法(甚至还会查找isXxx的标准命名方法)或者setter方法,如果找不到就查找_Xxx或者Xxx为名称的成员变量取值或者赋值,总之只要使用规范的命名方法和声明方法,KVC就可以处理。

3.dictionaryWithValuesForKeys:方法,通过传入key数组,返回一个成员变量名(不加下划线)和变量值的键值对组成的字典。

NSDictionary *dict = [s dictionaryWithValuesForKeys:[NSArray arrayWithObjects:@"name",@"age", nil]];

如果使用@来初始化数组,不必写nil(写了会报错,提示nil不是一个OC对象),应该如下书写:

NSDictionary *dict1 = [s dictionaryWithValuesForKeys:@[@"name",@"age"]];

打印出的dict值为:

{
age = 18;
name = John;
}

4.setValuesForKeysWithDictionnary: 方法,通过传入字典,初始化相应的键对应的成员变量(同前所述,非常智能的查找)的值为相应的的键值,在MVC设计模式中,模型初始化常用这个方法,一般是写在初始化方法中,通过字典初始化模型数据。

5. dictionaryWithObjects: forKeys: 方法通过传入对象和键名,生成一个 (键-对象) 键值对的字典,注意对非OC对象的包装。

6.key path称为键路径,如果要跨越一层模型数据访问第二层模型数据,例如学生拥有一个学生卡对象,学生卡内部也是个模型,如果要透过card对象访问卡号no属性,就需要通过card.no来调用set或者get方法,这时候可以使用setValue: forKeyPath: 方法,在KeyPath后传入card.no就可以设置no的值了,同样,使用valueForKeyPath:方法可以得到card.no的值。

7.假如有一个Group对象拥有一个Student对象数组,如果要获得所有的Student对象的name,可以使用valueForKeyPath方法返回name数组:

    Student *s = [[Student alloc] init];
s.age = 15;
s.name = @"John";
s.no = @"10010";
Student *s2 = [[Student alloc] init];
s2.age = 18;
s2.name = @"Rose";
s2.no = @"10011"; Group *g = [[Group alloc] init];
g.persons = @[s,s2]; NSArray *array = [g valueForKeyPath:@"persons.name"];

通过打印可以发现array内存放的为s和s2的name:

(
John,
Rose
)

8.键路径运算:

@count运算符表示计算一组值的平均值。这里也可以使用路径运算,例如Group.persons的@count结果 和 Group的"persons.@count" 的结果是一样的,可以把@count理解为具有集合特性的对象的一个成员变量,它表示集合中元素的个数

@sum.xxx 表示计算某个集合内部的xxx属性的和,注意如果是路径访问,使用类似books.@sum.price访问books内部成员的price来求和。

KVO的全称为key value observing,是一种监听对象属性变化的机制。

通过 addObserver...方法添加监听器,实现observerValueForKeyPath...来监听,通过removeObserver移除监听器。

下面演示一个例子,通过KVO监听ViewController类的name属性的变化,通过NSTimer产生随机的字符串赋给name,打印监听函数的输出,注意有监听就要有移除,要重写dealloc方法,注意ARC不要调super的dealloc方法。

- (void)viewDidLoad {
[super viewDidLoad]; [self addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil]; NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(changestr) userInfo:nil repeats:YES];
[timer fire]; } - (void)changestr{
self.name = [NSString stringWithFormat:@"%d change",arc4random()];
} - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{ NSLog(@"the keyPath : <%@> ofObject : <%@> is change to <%@>",keyPath,object,change); } - (void)dealloc{ [self removeObserver:self forKeyPath:@"name"]; }

打印出的数据为:

the keyPath : <name> ofObject : <<ViewController: 0x7d18ca00>> is change to <{
kind = 1;
new = "1844532638 change";
}>

(五十一)KVC与KVO详解的更多相关文章

  1. [五]基础数据类型之Short详解

      Short 基本数据类型short  的包装类 Short 类型的对象包含一个 short 类型的字段      原文地址:[五]基础数据类型之Short详解   属性简介   值为  215-1 ...

  2. “全栈2019”Java异常第十五章:异常链详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异 ...

  3. 第十一章、super()详解

    目录 第十一章.super()详解 一.引出super()来由 第十一章.super()详解 一.引出super()来由 原始用法: 在python类的方法中,要调用父类的某个方法,通常是类.方法() ...

  4. Python 自动化测试全攻略:五种自动化测试模型实战详解

    随着移动互联网的发展,软件研发模型逐步完善,软件交付质量越来越受到软件公司的重视,软件测试技术特别是自动化测试技术开始在软件系统研发过程中发挥着越来越重要的作用. 与传统的手工测试技术相比,自动化测试 ...

  5. View绘制详解(五),draw方法细节详解之View的滚动/滑动问题

    关于View绘制系列的文章已经完成了四篇了,前面四篇文章主要带小伙伴们熟悉一下View的体系的整体框架.View的测量以及布局等过程,从本篇博客开始,我们就来看看View的绘制过程.View的绘制涉及 ...

  6. 第五章 MVC之Bundle详解

    一.简述 Bundle,英文原意就是捆.收集.归拢.在MVC中的Bundle技术,也就是一个对css和js文件的捆绑压缩的技术. 它的用处: 将多个请求捆绑为一个请求,减少服务器请求数 压缩javas ...

  7. java基础(十五)----- Java 最全异常详解 ——Java高级开发必须懂的

    本文将详解java中的异常和异常处理机制 异常简介 什么是异常? 程序运行时,发生的不被期望的事件,它阻止了程序按照程序员的预期正常执行,这就是异常. Java异常的分类和类结构图 1.Java中的所 ...

  8. MP实战系列(十一)之封装方法详解(续一)

    之前写的封装方法详解,比较简要. 今天我主要讲增加和删除及其修改.查的话得单独再详讲. 增删改查,无论是Java或者C#等等,凡是对数据库操作的都离不开这四个. 一.增加方法讲解 MyBatis Pl ...

  9. 微服务之SpringCloud实战(五):SpringCloud Eureka详解

    Eureka详解 在第三节高可用中,实际已经讲解了服务的注册,只不过注册的是Eureka本身,原理相同,通过这几篇文章我相信大家对Eureka有了一定的了解,三个核心角色:服务注册中心.服务提供者和服 ...

随机推荐

  1. 剑指架构师系列-Nginx的安装与使用

    Nginx可以干许多事情,在这里我们主要使用Nginx的反向代理与负载均衡功能. 1.Nginx的下载安装 在安装Nginx前需要安装如下软件: GCC  Nginx是C写的,需要用GCC编译 PCR ...

  2. 链表的无锁操作 (JAVA)

    看了下网上关于链表的无锁操作,写的不清楚,遂自己整理一部分,主要使用concurrent并发包的CAS操作. 1. 链表尾部插入 待插入的节点为:cur 尾节点:pred 基本插入方法: do{ pr ...

  3. Node.js URL

    稳定性: 3 - 稳定 这个模块包含分析和解析 URL 的工具.调用 require('url') 来访问模块. 解析 URL 对象有以下内容,依赖于他们是否在 URL 字符串里存在.任何不在 URL ...

  4. Django 跨域请求处理

    参考https://blog.csdn.net/qq_27068845/article/details/73007155 http://blog.51cto.com/aaronsa/2071108 d ...

  5. ReactNative 4Android源码分析二: 《JNI智能指针之实现篇》

    文/Tamic http://blog.csdn.net/sk719887916/article/details/53462268 回顾 上一篇介绍了<ReactNative4Android源码 ...

  6. Tomcat如何实现WebSocket

    WebSocket协议属于HTML5标准,越来越多浏览器已经原生支持WebSocket,它能让客户端和服务端实现双向通信.在客户端和服务器端建立一条WebSocket连接后,服务器端消息可直接发送到客 ...

  7. Java进阶(四十四)线程与进程的特征及区别

    线程与进程的特征及区别 定义及特征 进程   指在系统中能独立运行并作为资源分配的基本单位,它是由一组机器指令.数据和堆栈等组成的,是一个能独立运行的活动实体. 进程的特征: 1.动态性:进程的实质是 ...

  8. Dynamics CRM2016 站点地图Bug之KnowledgeArticle不显示

    在CRM2016中对知识库功能进行了加强,新加入了KnowledgeArticle的实体,但在学习的过程中发现了微软的一个bug 下图是我在最新的2016online的版本上看到的service下的s ...

  9. ORACLE数据库学习之逻辑结构

     逻辑结构 数据库逻辑结构包含表空间.段.范围(extent).数据块和模式对象. (一)表空间 一个数据库划分为一个或多个逻辑单位,该逻辑单位称为表空间类似于sybase下的设备.(TABLES ...

  10. Android 访问assets下的文件

    assets下经常可以放一些比较大的资源,对于这些资源我们如何访问. 步骤 1.获取AssetManager. AssetManager am = getResources().getAssets() ...