美文网首页
KVO 学习

KVO 学习

作者: 化二缺 | 来源:发表于2020-05-05 16:14 被阅读0次
  • KVO key-Value Observing 键值监听 ,可以用于监听某个对象属性值的改变

使用了KVO监听的对象

  • runtime动态创建一个子类


    image.png

KVO探究

#import "learnKVOdeepVC.h"
@interface Person : NSObject
@property(nonatomic,strong) NSString * name;
@end
@implementation Person

@end

@interface learnKVOdeepVC ()
@property(nonatomic,strong) Person * person1;
@property(nonatomic,strong) Person * person2;
@end

@implementation learnKVOdeepVC

- (void)viewDidLoad {
    [super viewDidLoad];
    //不设置颜色 touchesBegan 无效 这个需要注意 
    self.view.backgroundColor = [UIColor whiteColor];
    self.person1 = [[Person alloc]init];
    self.person1.name = @"person1";
    
    self.person2 = [[Person alloc]init];
    self.person2.name = @"person2";
    
    
    NSLog(@"person1添加KVO监听之前 - %s %s", object_getClassName(self.person1),
          object_getClassName(self.person2));
    
    
  NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld ;
    [self.person1 addObserver:self forKeyPath:@"name" options:options context:@"123"];
    
    NSLog(@"person1添加KVO监听之后 - %s %s", object_getClassName(self.person1),
          object_getClassName(self.person2));
}

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    [self.person1 setName:@"哈哈"];
    
}

-(void)dealloc{
    [self.person1 removeObserver:self forKeyPath:@"name"];
}

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    
    NSLog(@"监听到的%@的%@属性值改变了 - %@ - %@",object,keyPath,change,context);
}
@end

输出

2020-05-06 09:49:50.766225+0800 HYZExplore[4119:64877] person1添加KVO监听之前 - Person Person
2020-05-06 09:49:50.766508+0800 HYZExplore[4119:64877] person1添加KVO监听之后 - NSKVONotifying_Person Person
2020-05-06 09:49:51.825428+0800 HYZExplore[4119:64877] 监听到的<Person: 0x600002f5a1c0>的name属性值改变了 - {
    kind = 1;
    new = "\U54c8\U54c8";
    old = person1;
} - 123

可见 person1的Class对象不再是Person 而是一个 NSKVONotifying_Person 的类对象

 NSLog(@"person1添加KVO监听之前 - %p %p", [self.person1 methodForSelector:@selector(setName:)],
           [self.person2 methodForSelector:@selector(setName:)]);
 NSLog(@"person1添加KVO监听之后 - %p %p", [self.person1 methodForSelector:@selector(setName:)],
           [self.person2 methodForSelector:@selector(setName:)]);

输出

 person1添加KVO监听之前 - 0x10b804510 0x10b804510
 person1添加KVO监听之后 - 0x7fff258e454b 0x10b804510

可见 person1的方法实现地址变了

  • KVO生成的class对象的isa 指向KVO 生成的class对象的元类,不会指向被观察的对象的元类

KVO 对象里面的方法

  • class方法
  NSLog(@"person1添加KVO监听之后 - %s %s", object_getClassName(self.person1),
          object_getClassName(self.person2));
 NSLog(@"person1添加KVO监听之后 - %@ %@", [self.person1 class],
             [self.person2 class]);

输出结果
NSKVONotifying_Person Person
Person Person
是不一样的
KVO的对象的class方法重写了 是为了隐蔽 NSKVONotifying_Person
屏蔽内部实现

探究2

- (NSString*)printMethodNamesOfClass:(Class)cls
{
    unsigned int count ;
    //获得方法数组
    Method  * methodlist = class_copyMethodList(cls, &count);
    
// 存储方法名
    NSMutableString * methodNames = [NSMutableString string];
    
    //遍历所有方法
    for(int i =0 ; i < count ; i++ ){
        //获取方法
        Method method = methodlist[i];
        //获取方法名
        NSString * methodName = NSStringFromSelector(method_getName(method));
        //拼接方法名
        [methodNames appendString: methodName];
        [methodNames appendString:@", "];
    }
    free(methodlist);
    return  methodNames;
}

 
   NSString * names = [self printMethodNamesOfClass:[self.person1 class]];
    
    NSLog(@"printMethodNamesOfClass = %@",names);
    
    Class realclass = NSClassFromString([NSString stringWithFormat:@"%s",object_getClassName(self.person1)] );
    
    NSString * names2 = [self printMethodNamesOfClass:
                         realclass];
    
    NSLog(@"printMethodNamesOfClass = %@",names2);

输出结果
printMethodNamesOfClass = .cxx_destruct, name, setName:,
printMethodNamesOfClass = setName:, class, dealloc, _isKVOA,
可见变成kvo对象了

总结

1.iOS用什么方法实现对一个对象的KVO?本质是什么?

  1. 利用RuntimeAPI动态生成的一个子类,并且让instance对象的isa指向这个全新的子类
  2. 当修改instance对象属性时,会调用Foundation的 _NSSetXXXValueAndNotify函数

willChangeValueForKey:
父类原来的setter
didChangeValueFoeKey:
内部会触发监听器(Oberser)的监听方法(-observeValueForKeyPath:ofObject:change:context:)

2.手动触发KVO?

  [self.person1 willChangeValueForKey:@"name"];
  [self.person1 didChangeValueForKey:@"name"];

3.直接修改成员变量会触发KVO么?

@interface Person:NSObject 
{
    @public 
    int  _age ;
}

Person * p =[ [Person alloc]init];

p->_age = 2;

这种不会触发 因为没有走setter

相关文章

  • KVO学习

    KVO机制学习 什么是KVO?   KVO是Key-Value-Observing的缩写,通过KVO机制对象可以得...

  • OC的KVO学习记录(2)

    仿写KVO的实现KVO原理参考可前一篇OC的KVO学习记录代码github地址:Sameny仿写KVO 注:关键代...

  • KVO学习笔记

    1.KVO初探学习2.KVO 底层原理探索 1.KVO初探学习 移除观察者的重要性 (IOS11之后说不移除是不对...

  • KVO&KVC分析

    KVO和KVC应用还是比较广泛的。所以,今天我们就重新再学习下它们,以加深记忆。 一、KVO 1、KVO(key-...

  • KVO学习

    KVO,俗称键值监听,可以用于监听某个对象属性值的改变。 先简单的演示下KVO的使用方式 点击手机屏幕,打击结果如...

  • KVO学习

    部分代码均可参考AFNetworking文件 1.KVO监听属性(自动监听) 1.1.注册监听 1.2.监听回调 ...

  • KVO 学习

    KVO key-Value Observing 键值监听 ,可以用于监听某个对象属性值的改变 使用了KVO监听的对...

  • KVC、KVO的本质

    这篇文章介绍KVC、KVO的本质。如果你对KVC、KVO不了解,推荐先查看其用法:KVC和KVO学习笔记[http...

  • KVO初探

    最好的学习文档是 KVO苹果官方文档 KVO三步曲 添加观察者 observer:注册KVO通知的对象。观察者必须...

  • iOS 底层探索之KVO

    KVO是Objective-C中的键值监听策略,本篇能学习到以下知识点1、KVO的使用方法大全2、KVO的底层如何...

网友评论

      本文标题:KVO 学习

      本文链接:https://www.haomeiwen.com/subject/pkwmghtx.html