KVO 使用及原理

KVO的基本原理大概是这样的

  当一个对象被观察时, 系统会新建一个子类NSNotifying_A ,在子类中重写了对象被观察属性的 set方法,  并且改变了该对象的 isa 指针的指向(指向了新建的子类) , 当属性的值发生改变了, 会调用子类的set方法, 然后发出通知

一. KVO 的基本使用

给_person对象 添加观察者self, 当person对象的name的值发生改变的时候, 会触发observer方法

_person = [Person new]; p.name = @"oldName"; //添加观察者 // [p addObserver:self forKeyPath:@"dog" options:NSKeyValueObservingOptionNew context:nil]; [_person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
// 所观察的对象的keyPath 发生改变的时候, 会触发
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    NSLog(@"%@",keyPath);
    NSLog(@"%@",change);

}

二.  当keyPath 为对象时, 改对象有许多属性, 怎么办?

在person类中,重写这个方法, 设置需要观察的属性 , 注意:"_dog.level"

//返回一个容器, 里面放的是NSString类型
+ (NSSet<NSString *> *)keyPathsForValuesAffectingValueForKey:(NSString *)key{

    NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key];
    //观察dog对象中的所有属性
    if ([key isEqualToString:@"dog"]) {
        keyPaths = [keyPaths setByAddingObjectsFromArray:@[@"_dog.level",@"_dog.age"]];
    }

    return keyPaths;
}

三. 手动触发KVO

系统默认该对象的所有属性 都能被观察到 ,重写下面方法, 可以单独设置某个属性不能被观察

//默认 yes, 默认自动观察所有属性
+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key{
    return YES;
}//返回NO, 则不能被默认观察到name
+ (BOOL)automaticallyNotifiesObserversOfName{
    return NO;
}
+ (BOOL)automaticallyNotifiesObserversOfAge{
    return YES;
}

当 name 发生改变的时, 手动触发, 发送通知

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    //手动发通知
    //即将改变(发一次通知)
    [_person willChangeValueForKey:@"name"];
     _person.name = @"dddd";
     //已经改变(发一次通知),一共发了两次通知
    [_person didChangeValueForKey:@"name"];
 }

四. 自定义KVO

根据kvo的原理, 可以自定义一个kvo, 建一个NSObject的分类, 添加方法

@interface NSObject (XSKVO)

- (void)xs_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context;

@end

通过runtime的方式, 动态创建一个类, 并给该类添加方法

#import "NSObject+XSKVO.h"
 #import <objc/runtime.h>

@implementation NSObject (XSKVO)

- (void)xs_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context{

    //1.新建一个类
    NSString *className = [@"XSKVO" stringByAppendingString: NSStringFromClass([self class])];
    Class newClass = objc_allocateClassPair([self class], className.UTF8String, 0);
     //注册类
    objc_registerClassPair(newClass);
    //2.修改 调用者类型
    object_setClass(self, newClass);

    //3.给子类添加set方法(子类里面没有set方法的)
    //OC方法:方法编号SEL ,方法实现IMP
    class_addMethod(newClass, @selector(setName:), xssetName, "");

}

/*
 隐藏的参数:
 self  方法的调用者
 _cmd  方法的编号

 */
void xssetName(id self,SEL _cmd, NSString *newName){
    NSLog(@"自定义的实现%@",newName);
    //方案一:通过消息机制 发送消息 -observeValueForKeyPath

}

@end

五. 其他

关于容器类(如:NSMutableArray)的观察, 当通过addObject: 向数组中添加对象, 不会触发KVO, 因为并没有触发set方法,

解决方法: 通过KVC 方法 - mutableArrayValueForKey:

原文地址:https://www.cnblogs.com/daxueshan/p/8313318.html

时间: 2024-10-11 17:45:42

KVO 使用及原理的相关文章

ios KVO的实现原理

首先给大家介绍一下KVO的使用场景:当某个对象的某个属性改变的时候,需要我们做出相应的处理事件.比如我们自定义下拉刷新,那么我们是如何得知用户要进行的下拉刷新数据操作呢,我们可以监听控件的frame,通过用户下拉该控件的时候,会修改该控件的frame.y属性,我们使用KVO监听这个属性.当这个属性的y值在某个范围,我们认为是下拉刷新操作.我们可以去进行数据请求.因为现在下拉刷新的第三方框架有很多,所以很少有人关注下拉刷新的实现原理. 又比如,我们经常使用的网络请求的第三方AFN,它内部监听网络下

KVO内部实现原理

// // ViewController.m // KVO内部实现原理 // // Created by sw on 15/4/13. // Copyright © 2015年 sw. All rights reserved. // #import "ViewController.h" #import "Person.h" @interface ViewController () @end @implementation ViewController - (void

KVO的实现原理

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

KVO底层实现原理,仿写KVO

这篇文章简单介绍苹果的KVO底层是怎么实现的,自己仿照KVO的底层实现,写一个自己的KVO监听 #pragma mark--KVO底层实现 第一步:新建一个Person类继承NSObject Person.h #import <Foundation/Foundation.h> @interface Person : NSObject //字符串类型的属性name @property (nonatomic, strong) NSString *name; @end Person.m #impor

KVO底层实现原理

(KVO)键值观察者底层解析 涉及到了runtime,关于isa指针 手动实现键值观察(代码示例) 被观察的对象Target(重写setter/getter方法)Target.h @interface Target : NSObject { int age; } // for manual KVO - age- (int) age; - (void) setAge:(int)theAge; @end Target.m @implementation Target - (id) init{ sel

KVC与KVO的实现原理

|KVC的用法 1.KVC既键值编码(Key Value Coding),基于NSKeyValueCoding协议,它是以字符串的形式来操作对象的成员变量,也就是通过字符串key来指定要操作的成员变量.基本操作如: setValue:forKey:为成员变量赋值.如:[student setValue:@"大明" forKey:@"name"]; valueForKey:获取指定的成员变量.如:NSString *name = [student valueForKe

iOS 的 KVC &amp; KVO的底层实现原理

KVO 内部实现原理 1. KVO 是基于runtime机制实现的. 2. 当某个类的对象第一次被观察时,系统就会在运行期动态的创建该类的一个派生类,在这个派生类中重写基类中任何被观察属性的setter方法; 派生类在被重写的setter方法中实现真正的通知机制 (Person -> NSKVONotifying_Person) 1.KVC,即是指 NSKeyValueCoding,一个非正式的Protocol,提供一种机制来间接访问对象的属性.而不是通过调用Setter.Getter方法访问.

转:KVC/KVO原理详解及编程指南

作者:wangzz 原文地址:http://blog.csdn.net/wzzvictory/article/details/9674431 转载请注明出处 如果觉得文章对你有所帮助,请通过留言或关注微信公众帐号wangzzstrive来支持我,谢谢! 前言: 1.本文基本不讲KVC/KVO的用法,只结合网上的资料说说对这种技术的理解. 2.由于KVO内容较少,而且是以KVC为基础实现的,本文将着重介绍KVC部分. 一.简介 KVC/KVO是观察者模式的一种实现,在Cocoa中是以被万物之源NS

KVO实现原理剖析

最近看了一些关于ios runtime相关的资料,看到网上有人发的关于kvo的实现原理,刚好有时间自己研究了一遍,整理下分享给初学的朋友. KVO的全称是Key-Value Observing,它实现了一种机制,对所关心的属性对象添加观察者,当属性值发生变化时会得到通知,我们可以对变化做相应的处理.看过设计模式的同学应该知道,这是一种典型的观察者模式.KVO的最大优点就是底层框架已经支持,开发人员不需要实现属性值发生变化时发送通知的方案,这样就大大减少开发的工作量.其次,KVO框架很强大,可以支