KVC与KVO的实现原理

|KVC的用法

1、KVC既键值编码(Key Value Coding),基于NSKeyValueCoding协议,它是以字符串的形式来操作对象的成员变量,也就是通过字符串key来指定要操作的成员变量。基本操作如:

  • setValue:forKey:为成员变量赋值。如:[student setValue:@"大明" forKey:@"name"];
  • valueForKey:获取指定的成员变量。如:NSString *name = [student valueForKey:@"name"];

2、用KVC操作成员变量的底层实现,是runtime的一个典型。就拿成员变量name来说吧,一般按如下顺序执行:

  • 程序先尝试调用name的setter或getter方法,就是先调用setName或name方法来设置或获取成员变量。
  • 如果该类没有提供setter或者getter方法,则KVC机制将会搜索该类中名为_name的成员变量。这时无论该成员变量定义在接口部分还是实现部分,KVC的代码底层都会对_name进行赋值或者获取操作。
  • 如果该类既没有setter或者getter方法,也没有_name成员变量,则KVC机制将会搜索该类中名为name的成员变量。这时无论该成员变量定义在接口部分还是实现部分,KVC的代码底层都会对name进行赋值或者获取操作。
  • 如果以上3步都没能找到指定的成员变量,则程序将会执行setValue:forUndefinedKey:或者valueForUndefinedKey:方法抛出异常,默认是终止程序。

3、对于不存在的key怎么处理呢?默认情况下会抛出NSUnknownKeyException异常,并终止程序。

此时可以直接在类的实现部分重写setValue:forUndefinedKey:和valueForUndefinedKey:方法,当KVC找不到指定的成员变量时,会调用这两个方法,通过重写这两个方法可以方便的定制自己的处理方案。

4、setNilValueForKey:方法的调用。

当用KVC的方式把基本数据类型(如int、float等)设置为nil时,会调用成员变量所属类的setNilValueForKey:方法,抛出NSInvalidArgumentException异常,并终止程序。

此时在该类的实现中重写setNilValueForKey:做相应的处理即可。

5、KVC操作对象的复合属性。

复合属性:一个类的属性是另一个类的对象,这个对象的属性就是就是复合属性,比如Person类有个Student类型的属性student,Student类有个name属性,name相对于Person类就是个复合属性。这个复合属性在KVC机制中被称为key路径,即student.name。

在KVC机制中操作key路径的方法如下:

  • setValue:forKeyPath:根据key路径设置属性值。
  • valueForKeyPath:根据key路径获取属性值。

通过KVC操作对象的性能比通过setter和getter方法要差,但是通过KVC比较灵活。

|KVO的用法

KVO即键值监听(Key Value Observe),基于NSKeyValueObserving协议,用于监听属性值的改变(通常是数据模型)。

KVO的用法分三步:

  1. 为对象指定的key路径注册监听器 -> addObserver:forKeyPath:options:context:。
  2. 重写监听方法以得到最新修改的数据 -> observeValueForKeyPath:ofObject:change:context:。
  3. 删除指定key路径的监听器 -> removeObserver:forKeyPah:或者removeObserver:forKeyPath:context。

参数说明:

observer: 观察对象。

forKeyPath:对象的复合属性。

options分别是:

  • NSKeyValueObservingOptionNew:把更改之前的值提供给处理方法
  • NSKeyValueObservingOptionOld:把更改之后的值提供给处理方法
  • NSKeyValueObservingOptionInitial:把初始化的值提供给处理方法,一旦注册,立马就会调用一次。通常它会带有新值,而不会带有旧值。
  • NSKeyValueObservingOptionPrior:分2次调用,在值改变之前和值改变之后。
  • 0:就代表不带任何参数进去。

context: 可以带入一些参数,其实这个挺好用的,任何类型都可以,自己强转就好了。

change:  字典里的key对应options里的NSKeyValueObservingOptionNew、NSKeyValueObservingOptionOld等。

  •  1 #import "ViewController.h"
     2 #import "Person.h"
     3 #import "Student.h"
     4
     5
     6 @interface ViewController ()
     7 @property (strong, nonatomic) Person *person;
     8 @property (strong, nonatomic) Student *stu;
     9 @end
    10
    11 @implementation ViewController
    12 - (void)viewDidLoad {
    13     [super viewDidLoad];
    14     Person *person = [[Person alloc] init];
    15     self.person = person;
    16     Student *stu = [[Student alloc] init];
    17     self.stu = stu;
    18     person.height = 1.5;
    19     person.student = stu;
    20     stu.height = 1.0;
    21     stu.age = 10;
    22     [person addObserver:self forKeyPath:@"height" options:NSKeyValueObservingOptionNew context:nil];
    23     [person addObserver:self forKeyPath:@"student.height" options:NSKeyValueObservingOptionNew context:nil];
    24     [stu addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew context:nil];
    25     for (int i = 1; i < 4; i++) {
    26         [person setValue:@(person.height + i) forKey:@"height"];
    27         [person setValue:@(person.student.height + i) forKeyPath:@"student.height"];
    28         [stu setValue:@(stu.age + i) forKey:@"age"];
    29     }
    30
    31     NSLog(@":person.height = %@,    stu.height = %@,    stu.age = %@", [person valueForKey:@"height"], [person valueForKeyPath:@"student.height"], [stu valueForKey:@"age"]);
    32 }
    33
    34 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
    35     NSLog(@"\n--------------------\n被修改的KeyPath:%@\n被修改的对象:%@\n被修改后的值:%@\n被修改的上下文:%@\n\n\n", keyPath, object, change[NSKeyValueChangeNewKey], context);
    36 }
    37
    38 - (void)dealloc {
    39     [self.person removeObserver:self forKeyPath:@"height"];
    40     [self.person removeObserver:self forKeyPath:@"student.height"];
    41     [self.stu removeObserver:self forKeyPath:@"age"];
    42 }
    43
    44 @end
时间: 2024-10-13 10:10:21

KVC与KVO的实现原理的相关文章

OC学习篇之---KVC和KVO操作

前一篇文章我们介绍了OC中最常用的文件操作:http://blog.csdn.net/jiangwei0910410003/article/details/41875015,那么今天来看一下OC中的一个比较有特色的知识点:KVC和KVO 一.KVC操作 OC中的KVC操作就和Java中使用反射机制去访问类的private权限的变量,很暴力的,这样做就会破坏类的封装性,本来类中的的private权限就是不希望外界去访问的,但是我们这样去操作,就会反其道而行,但是我们有时候真的需要去这样做,哎.所以

iOS开发中KVC、KVO简介

在iOS开发中,KVC和KVO是经常被用到的.可以使用KVC对对象的属性赋值和取得对象的属性值,可以使用KVO监听对象属性值的变化.简单介绍一下KVC和KVO. 一:键值编码(KVC) KVC,全称 Key Value Coding(键值编码),是OC 语言的一个特性,使用KVC,可以对对象的属性进行动态读写. KVC的操作方法由 NSKeyValueCoding协议提供,而NSObject已经实现了这个协议,因此OC中的几乎所有对象都可以使用KVC操作.常用的KVC操作方法有: (1)设置属性

KVC、KVO实现过程

1.KVC的实现过程 以 [object setValue:@"134567" forKey:@"uid"];为例子,来探究KVC的实现过程 第一步:搜索1.首先搜索setKey:方法.(key指成员变量名, 首字母大写)2.上面的setter方法没找到, 如果类方法accessInstanceVariablesDirectly返回YES. 那么按 _key, _isKey,key, iskey的顺序搜索成员名.(NSKeyValueCodingCatogery中实

KVC 和 KVO 简单总结

KVC: key value coding,键值编码.是一种通过使用属性的名称(key)来间接访问对象属性的方法.这个方法可以不用通过 setter/getter 方法来访问对象的属性.该方法使用的实质是,是使用 valueForKey来代替 getter 方法, setValueForKey 来代替 setter 方法. KVC 常用的方法: - (id)ValueForKey:   通过 key 值读取对象的属性 -(id)setValue: forKey: 通过 key 的值来使用属性 -

【iOS】KVC 与 KVO

一.KVC与KVO *"KVC":key value Coding(键值编码) *目的:间接的修改或获取对象的属性,降低程序(类与类)之间的耦合度. *"KVO":key value Observer(键值观察),观察者模式.(检测模型变化用的多) *目的:通常用于观察某个对象的某个属性发生变化时,及时做出相应. 二.KVC的使用方式 KVC被称为iOS开发平台的大招!!! 能快速修改对象属性. *[p1setValue:@"xxxx"forKe

KVO的实现原理

摘自:iOS--KVO的实现原理与具体应用 1 KVO是什么? KVO是Objective-C对观察者模式的一种实现,另外一种是通知机制(notification) KVO提供一种机制,指定一个被观察对象(例如A类),当对象的某个属性(例如A中的字符串name)发生更改时,对象会获得通知,并做出相应的处理. 在MVC设计架构下的项目,KVO机制很适合实现model模型和view视图之间的通讯. 例如:代码中,在模型类A创建属性数据,在控制器中创建观察者,一旦属性数据发生改变,观察者就会收到通知,

ios开发runtime学习五:KVC以及KVO,利用runtime实现字典转模型

一:KVC和KVO的学习 #import "StatusItem.h" /* 1:总结:KVC赋值:1:setValuesForKeysWithDictionary实现原理:遍历字典,得到所有的key,value值,再利用kvc, setVaue forkey来为value赋值 2: [item setValue:@"来自即刻笔记" forKey:@"source"],内部的底层实现, 1.首先去模型中查找有没有setSource,找到,直接调用

(转载)OC学习篇之---KVC和KVO操作

前一篇文章我们介绍了OC中最常用的文件操作,那么今天来看一下OC中的一个比较有特色的知识点:KVC和KVO 一.KVC操作 OC中的KVC操作就和Java中使用反射机制去访问类的private权限的变量,很暴力的,这样做就会破坏类的封装性,本来类中的的private权限就是不希望外界去访问的,但是我们这样去操作,就会反其道而行,但是我们有时候真的需要去这样做,哎.所以说有些事不是都是顺其自然的,而是需要的时候自然就诞生了. 下面就来看一下这种技术的使用: Dog.h 1 // 2 // Dog.

iOS KVC 和 KVO 区别简单总结

KVC: key value coding,键值编码.是一种通过使用属性的名称(key)来间接访问对象属性的方法.这个方法可以不用通过 setter/getter 方法来访问对象的属性.该方法使用的实质是,是使用 valueForKey来代替 getter 方法, setValueForKey 来代替 setter 方法. KVC 常用的方法: - (id)ValueForKey:   通过 key 值读取对象的属性 -(id)setValue: forKey: 通过 key 的值来使用属性 -