深入理解一手KVO

作者: uncleRX | 来源:发表于2018-03-29 17:35 被阅读6次

Key-Value Observing : 键值监听

KVO则必须实现NSKeyValueObServing协议,但不用担心,因为NSObject已经实现了该协议,因此几乎所有的ObjC对象都可以使用KVO

kvo是用来观察监听对象的属性变化(非成员变量)

@interface Person : NSObject
{
   @public
   NSString *_var1;
}
@property (nonatomic, copy) NSString *var2;

@end

验证代码:

self.p1 = [[Person alloc]init];
[self.p1 addObserver:self forKeyPath:@"var1" options:(NSKeyValueObservingOptionNew) context:nil];
[self.p1 addObserver:self forKeyPath:@"var2" options:(NSKeyValueObservingOptionNew) context:nil];

改变值:
self.p1.var2 = @"222";
self.p1->_var1 = @"111";

-----------------
输出结果:  222

来给监听加个断点,看下做了什么事情

xfQ+Nw0YmskAAAAAElFTkSuQmCC.png

我们可以过掉监听代码之后,person的类型虽然还是person类型,但是内部的isa指针已经指向另外一个类了,
这个类是动态生成的.

这里直接给出结果:
kvo其实是重写了set方法,动态创建该类的子类对象,然后子类属性值改变了之后通知给观察者

注意一点:

继承不意味着子类拥有父类所有的方法,继承意味着,子类方法里面没有这个方法,系统会去父类里面去寻找这个方法

介绍1个不常用的参数:
监听到通知之后的

change:(NSDictionary<NSKeyValueChangeKey,id> *)change

里面有个 new

知道这些知道,我们完全可以手动实现一个

步骤:

1.创建NSObject分类,实现动态子类以及重写改类的set方法

2.在使用的地方调用

代码如下:

@implementation NSObject (RXKvo)

- (void)RXKvo_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context {
    //新建类
    Class newClass = objc_allocateClassPair(self.class, @"RXPerson".UTF8String, 0);
    //注册类
    objc_registerClassPair(newClass);
    //添加方法
    class_addMethod(newClass, @selector(setVar2:), (IMP)changeFunction, "v@:");
    //修改类型
    object_setClass(self, newClass);
}

void changeFunction(id self,SEL _cmd,NSString *var) {
    NSLog(@"%@",var);
}

调用:

kRtFt+vzLywAAAABJRU5ErkJggg==.png

同理p1的类型是子类: RXPerson

如何使用kvo监听容器类的变化

一个需求,数据源数组变化之后需要立即刷新视图, kvo监听是一个比较好的方法.

但是会发现当你用数组去 addObject: 的时候,是不会收到任何值的变化的通知.

代码如下:

image.png

原因: 之前已经说过了是通过重写对象的set方法,由于数组里的 addObject: 并没有重写.所以肯定不管怎么变化都不会收到通知的


解决方法: 利用kvc的特性
NSMutableArray *temArr = [self.p1 mutableArrayValueForKey:@"sonArr"];
[temArr addObject:@"1"];
image.png

大家可以看到通过:
mutableArrayValueForKey:这种形式返回一个新创建的子类
举一反三 集合类会有类似的方法:

mutableArrayValueForKey:
mutableOrderedSetValueForKey:
mutableSetValueForKey:
......
介绍下键值对里 kind的值
typedef NS_OPTIONS(NSUInteger, NSKeyValueChange) {
    NSKeyValueChangeSetting = 1, //值发生变化 kind=1
    NSKeyValueChangeInsertion = 2, //插入
    NSKeyValueChangeRemoval = 3, //移除
    NSKeyValueChangeReplacement = 4 //替换
};

其他拓展

objc_msgSend() 函数默认会包含几个参数,我们在buildSetting 搜索 send
我们把 objc_msgSend 语法检查关闭,我们可以直接调用

//第一个参数是调用者,第二个参数是方法,第三个是参数,可继续添加多个参数
objc_msgSend(self.p1, @selector(setVar2:),@"111",@"111");
重点在于参数

//IMP指针函数默认是带形参的,严格依照顺序排列,参数名可以随意修改
void changeFunction(id self,SEL cmd,NSString *var ......) {
}

设备的CPU架构类型(指令集)
模拟器:
4s-5: i386
5s(包括5S)以后: x86_64

真机:
5c以前是: arm32位架构(5c是32位性能最强的机型)
5s之后架构: arm64 
在x86架构下,也就是模拟器

objc_msgSend()在不同架构下如上代码 发送的参数 收集到的结果并不一致,是因为里面定义的类型在不同架构下的参数是不一样,

代码演示:

//值变化代码
objc_msgSend(self.p1, @selector(setVar2:),@"111");

//关联函数代码
class_addMethod(NewClass, @selector(setVar2:), (IMP)changeFunction,"");

//打印值变化代码
void changeFunction(id self,SEL cmd,NSString *var) {
    NSLog(@"收到..%@",var);
}

//输出结果
---------------------------------------
//在arm64:
2018-03-29 17:14:13.253638+0800 TranslateVoice[2426:1737249] 收到..{(
    <UITouch: 0x15bd20220> phase: Began tap count: 1 force: 0.000 window: <UIWindow: 0x15be0cbc0; frame = (0 0; 375 667); autoresize = W+H; gestureRecognizers = <NSArray: 0x1c424abc0>; layer = <UIWindowLayer: 0x1c402af20>> view: <UIView: 0x15be0db30; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x1c402b420>> location in window: {138.5, 368.5} previous location in window: {138.5, 368.5} location in view: {138.5, 368.5} previous location in view: {138.5, 368.5}
)}

---------------------------------------

//x86下:
2018-03-29 17:16:14.039398+0800 TranslateVoice[26380:578592] 收到..111
2018-03-29 17:16:14.220402+0800 TranslateVoice[26380:578592] 收到..111

结尾: 有一年多没更新了,以后会陆续把笔记整理出来开放,这些笔记只是我自己在当时所理解的东西,难免存在差异,有理解错误的地方希望可以提出来纠正

相关文章

  • 深入理解一手KVO

    Key-Value Observing : 键值监听 KVO则必须实现NSKeyValueObServing协议,...

  • 深入理解KVO

    iOS | KVO | Objective-C KVO的本质是什么,如何手动触发KVO? 1.什么是KVO KVO...

  • 深入理解KVO

    KVO KVO全程是Key Value Observer,键值监听机制。底层实现机制是isa-swizzing K...

  • 深入理解KVO

    先来说说什么是KVO,KVO全称为Key Value Observing,键值监听机制,由NSKeyValueOb...

  • 深入理解KVO机制

    什么是KVO机制 KVO,全称是key_value_Observing,是ios中的一种设计模式,名为观察者模式,...

  • 高质量博文

    深入理解KVO MVC Tang 一只魔法师的工坊 SWIFT官网

  • KVO的原理

    KVO基本原理: KVO深入原理: 适用于:

  • 深入理解KVC与KVO

    KVC 介绍:https://www.jianshu.com/p/45cbd324ea65[https://www...

  • swift中KVO和属性观察器

    开篇提醒:OC中的KVO及其KVO的基础知识可参见:深入runtime探究KVO Swift中,原本没有KVO模式...

  • iOS KVO 和 KVC 深入理解

    无论是在我们的今后的工作当中还是面试找工作当中,这两个知识点是十分重要的,有些同学们对这方面的知识还是不是很了解,...

网友评论

    本文标题:深入理解一手KVO

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