当前位置:网站首页>Runtime - KVC, KVO principle
Runtime - KVC, KVO principle
2022-08-08 05:56:00 【chabuduoxs】
KVC是什么?
KVC是Key Value Coding的缩写,意思是键值编码. 在iOS中,Provides a method by using the name of the property(也就是Key)Methods to indirectly access object properties,This method can not passgetter/settermethods to access object properties. 用KVCA mechanism for indirectly accessing object properties.通常我们使用valueForKey 来替代getter 方法,setValue:forKey来代替setter方法.
常用API:
- (void)setValue:(id)value forKeyPath:(NSString *)keyPath;
- (void)setValue:(id)value forKey:(NSString *)key;
- (id)valueForKeyPath:(NSString *)keyPath;
- (id)valueForKey:(NSString *)key;
setValue:forKey:和valueForKey:Can only be used to access properties of the current object,而keyPathCan access the attributes of the by the current object,Can be put down layer by layer.
简单举个例子:
#import <Foundation/Foundation.h>
#import "Car.h"
NS_ASSUME_NONNULL_BEGIN
@interface Person : NSObject
@property (nonatomic, assign) NSInteger age;
@property (nonatomic, strong) Car* car;
@end
NS_ASSUME_NONNULL_END```
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface Car : NSObject
@property (nonatomic, strong) NSString* name;
@end
#import "ViewController.h"
#import "Person.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
Person* person = [[Person alloc] init];
person.car = [[Car alloc] init];
// KVC
[person setValue:@"20" forKey:@"age"];
NSLog(@"%@", [person valueForKey:@"age"]);
[person setValue:@111 forKeyPath:@"car.name"];
NSLog(@"%@", [person valueForKeyPath:@"car.name"]);
}
KVC的底层原理
KVC赋值
keypath的底层和key是同理的,下面分析一个key的流程,On an online understand chart.
Analyze the steps below:
- 首先第一步,Find the class first
setter方法,首先会把参数key的首字母大写,如何根据Key去查找对应的setter方法,包括setKey和_setKey,If found, call this method and pass the parametersvalue,To modify the value,如果没有找到setter方法,Just go back and look at this class+accessInstanceVariablesDirectlyreturn value of class method(Can you directly access member variables?,默认为YES),如果不能直接访问,就会报错,并且触发“setValue:forUndefinedKey:"方法. - If you can access member variables,The corresponding member variables will be searched in order,
_key,_isKey,key,isKey,If the corresponding member variable is found,Just assign a value directly to the member variable,(如果设置了KVO的话,此时会触发KVO,因为KVC在此处,也调用了willChangeValueForKey:和didChangeValueForKey:方法),If the member variable is not found,就会报错,并且触发“setValue:forUndefinedKey:"方法.
KVC取值

- Similar to the above process,just search firstgetter方法,按照getKey,key,isKey,_key顺序查找
- 如果没有找到getter方法,Just go back and look at this class
+accessInstanceVariablesDirectlyreturn value of class method(Can you directly access member variables?,默认为YES),如果不能直接访问,就会报错,并且触发“valueForUndefinedKey:"方法. - If you can access member variables,The corresponding member variables will be searched in order,
_key,_isKey,key,isKey,如果没找到,就会报错,并且触发“valueForUndefinedKey:"方法.
KVO?
KVO的全称是Key-Value Observing,俗称“键值监听”,可以用于监听某个对象属性值的改变.
使用KVOThere are only three key points:who was observed:That is, you want to observe which object and which attribute value changes.;who is the observer:who observes this object,After determining may be added to the objectKVOAnd remove the objectKVO了;Observer callback methods:Method triggered after object property changes.
举个例子:
#import "ViewController.h"
#import "Person.h"
@interface ViewController ()
@property (nonatomic, strong) Person* person;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.person = [[Person alloc] init];
self.person.car = [[Car alloc] init];
// KVO
// 给person添加观察者
[self.person addObserver:self forKeyPath:@"age" options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:nil];
// KVC
[self.person setValue:@"20" forKey:@"age"];
NSLog(@"%@", [self.person valueForKey:@"age"]);
[self.person setValue:@111 forKeyPath:@"car.name"];
NSLog(@"%@", [self.person valueForKeyPath:@"car.name"]);
}
- (void)dealloc {
// 移除person对象的KVO
[self.person removeObserver:self forKeyPath:@"age"];
}
// 回调方法
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
NSLog(@"被观察对象%@的%@属性发生变化:%@", object, keyPath, change);
}
@end
For specific use and parameter meanings, please refer to my previous blog——简单使用KVO

KVO底层原理
Since it is usedRuntime实现的KVO,就来探索一下,到底是如何实现的.
先下结论.
- First of all in use at runtimeRuntimeTo this class to create a new subclass,And will be usedKVO的instance的isaPointer to the new class.At this point, the instance object is no longer the original class.,but belongs to the newly created subclass.
- Next, this class will override the original class andNSObject类的部分方法,结合之前KVC找setter方法,The most important thing we can think of is overriding instance methodssetter.
- 重写后的setterThe main three processes:首先调用willChangeValueForKey:Indicates that the value is about to be modified,then find the objectsetter方法:To actually modify the value of the member variable,最后调用didChangeValueForKey:And in this method implement the observer to call the observer callback method.
About pseudo code can look at it:
@interface NSKVONotifying_Person : Person
@end
@implementation NSKVONotifying_Person
- (void)setAge:(int)age
{
_NSSetIntValueAndNotify();
}
// 伪代码
void _NSSetIntValueAndNotify()
{
[self willChangeValueForKey:@"age"];
[super setAge:age];
[self didChangeValueForKey:@"age"];
}
- (void)didChangeValueForKey:(NSString *)key
{
// 通知监听器,某某属性值发生了改变
[oberser observeValueForKeyPath:key ofObject:self change:nil context:nil];
}
// 屏幕内部实现,隐藏了NSKVONotifying_MJPerson类的存在
- (Class)class
{
return [Person class];
}
- (void)dealloc
{
// 收尾工作
}
- (BOOL)_isKVOA
{
return YES;
}
@end

边栏推荐
- Hundreds of billions, large-scale: performance tuning practice of Tencent's super-large Apache Pulsar cluster
- 毕设——基于人脸表情的桌面交互精灵设计(分享一下成果,附上人脸表情的数据集和自己训练出来yolov5模型以及基于PYQT5运行yolov5的交互界面)
- 轮播文字! QPainter
- 并查集按秩合并rank数组
- MySQL5
- Typescript 命名空间
- webstorage
- Connect two tables to update the third table (updata) in postgresql
- Promise的使用与async/await的使用
- 卷积神经网络 图像识别,卷积神经网络 图像处理
猜你喜欢
随机推荐
Redis set to start automatically at boot
人体神经元细胞分布图片,神经元人体分布大图
0 dictionary tree/string medium LeetCode676. Implement a magic dictionary
字符串哈希 哈希值
Rust development - Struct usage example
pta补坑简单图论
分布式事务 :可靠消息最终一致性方案
Object.prototype.toString()如何判断数据类型及注意点
Week 8 Transformer Language Models and Implications
基本工具-NETCAT(telnet-banner、传输文本信息)
flex布局缺点
clue binary tree
[Untitled] I haven't thought of a name yet
C语言日记 11 switch语句(分支结构程序设计)
MySQL5
Disadvantages of flex layout
Flutter 教程之高效且精美的滚动组件Slivers (教程含源码)
Postman显示验证码图片(base64字符串)
Connect two tables to update the third table (updata) in postgresql
tkinter-TinUI-xml combat (7) PDF paging and merging








