OC面试题- kvc和KVO的区别,及其本质

一般的面试题喜欢问kvc和kvo的区别,实际上这两者关系真心不大,能够联系上的就是都是键值对的形式存在的(k-v),kvc调用会调用到kvo(如果设置过监听),都是使用的set函数

其它的就基本没啥关系了

kvo的本质:

#import "ViewController.h"
#import "Person.h"
#import <objc/runtime.h>
@interface ViewController ()
@property (nonatomic,strong)Person *person;
@property (nonatomic,strong)Person *person1;
@end

@implementation ViewController

-(void)printMethodForClass:(Class)cls
{
    unsigned int count ;
    Method *methods = class_copyMethodList(cls, &count);
    for(int i = 0; i < count; i++)
    {
        Method method = methods[i];
        NSLog(@"%@" , NSStringFromSelector(method_getName(method)));
    }
    free(methods);
}

- (void)viewDidLoad {
    [super viewDidLoad];
    NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld;
    self.person = [[Person alloc] init];
    self.person1 = [[Person alloc] init];
    NSLog(@"监听之前%p,%p",[self.person methodForSelector:@selector(setMoney:)],[self.person1 methodForSelector:@selector(setMoney:)]);    //监听之前0x10ca74cf0,0x10ca74cf0
    NSLog(@"监听之前元类对象%p,%p",object_getClass(object_getClass(self.person)),
                                object_getClass(object_getClass(self.person1))); //监听之前元类对象0x10ca7c800,0x10ca7c800
    [self.person addObserver:self forKeyPath:@"money" options:options context:nil];
    [self.person addObserver:self forKeyPath:@"age" options:options context:@"123"];
    NSLog(@"监听之后%p,%p",[self.person methodForSelector:@selector(setMoney:)],[self.person1 methodForSelector:@selector(setMoney:)]); //监听之后0x7fff207bf79f,0x10ca74cf0
    NSLog(@"监听之后元类对象%p,%p",object_getClass(object_getClass(self.person)),
                                object_getClass(object_getClass(self.person1)));  //监听之后元类对象0x600000c28510,0x10ca7c800
    [self printMethodForClass:object_getClass(self.person)];
    // setAge:
    // setMoney:
    // class
    // dealloc
    // _isKVOA
    NSLog(@"Person1");
    [self printMethodForClass:object_getClass(self.person1)];
    //  setMoney:
    //  money
    // Do any additional setup after loading the view.
}

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    self.person.money = 30;
}

-(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    self.person.age = 40;
    self.person1.age = 30;
}

-(void)dealloc
{
    [self.person removeObserver:self forKeyPath:@"money"];
    [self.person removeObserver:self forKeyPath:@"age"];
}
- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSKeyValueChangeKey, id> *)change context:(nullable void *)context
{
    NSLog(@"change%@",change);
    NSLog(@"keypath%@",keyPath);
}

可以看的出来,person在设置之前和设置之后,连isa的指向地址都变了,而person1没设置过所以没变化,实际上的kvo设置监听之后会创建一个新类,这个类会继承Person然后重写Person的set函数,然后调用自己的- (void)willChangeValueForKey:(NSString *)key

 -(void)didChangeValueForKey:(NSString *)key 等等这些方法,然后又接受过本地传入的self调用

- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSKeyValueChangeKey, id> *)change context:(nullable void *)context,这个逻辑就很像delegate模式,但又不一样

以此来实现值得监听

kvc的本质:

kvc本质就是找set get方法,比如

Person *person = [[Person alloc] init];
[person setValue:@20 forKey:@"age"];    
NSLog(@"%@",[person valueForKey:@"age"]);

kvc是setvalue和valueForkey,本身是键值对形式没啥好说的,原理就是setvalue去找set函数,valueforkey去找对应的get函数,比如传入的是age 会寻找getAge age _age  isAge这些,优先找的是getAge,set也差不多...但我想了下这么写代码效率不会很低么,一方面要搜索多个,另一方面敲错个字母,又得排查半天的错误

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值