美文网首页
iOS 利用runtime手动实现KVO

iOS 利用runtime手动实现KVO

作者: 魔鬼分界线 | 来源:发表于2019-05-31 17:41 被阅读0次

KVO原理:调用监听对象属性的方法,动态创建一个继承自该对象所属类的子类,然后重写该属性的setter方法,在setter方法类调用willChangeValueForKey:didChangeValueForKey:方法来触发observeValueForKeyPath:ofObject:change:context:方法。
大概看了一下,大多数手动实现KVO都并没有做到真正动态创建类,而是手动。本文主要是动态创建继承类动态重写setter方法

直接贴代码吧,注释都在代码里面。
首先创建NSObject分类NSObject+XKVO暴露接口:
.h

#import <Foundation/Foundation.h>

@interface NSObject (XKVO)

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

@end

.m

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

@implementation NSObject (XKVO)

// 属性:用于保存监听对象
static char *kObserver = "kObserver";
- (void)setObserver:(id)observer {
    objc_setAssociatedObject(self, kObserver, observer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (id)observer {
    return objc_getAssociatedObject(self, kObserver);
}

void setterMethod(id self, SEL _cmd, id obj) {
    
    /* 根据_cmd和属性列表获取属性名和属性对应的old value数据 */
    NSString *name = NSStringFromSelector(_cmd);
    NSString *keyPath = [[name lowercaseString] substringFromIndex:3];
    keyPath = [keyPath substringToIndex:keyPath.length-1];
    
    id oldValue ;
    
    unsigned int count ;
    Ivar *ivarlist = class_copyIvarList([self superclass], &count);
    for (int i = 0; i < count; i++) {
        Ivar thisivar = ivarlist[i];
        NSString *name = [NSString stringWithUTF8String:ivar_getName(thisivar)];
        NSString *properName = [name substringFromIndex:1];
        name = [[name lowercaseString] substringFromIndex:1];
        BOOL isEqual = [name isEqualToString:keyPath];
        if (isEqual) {
            keyPath = properName;
            oldValue = [self valueForKey:keyPath];
            break;
        }
    }
    
    /* 调用父类的setter方法,保证设置数据不被干扰 */
    Method sm = class_getInstanceMethod([self superclass], _cmd);
    IMP imp = method_getImplementation(sm);
    imp(self, _cmd, obj);
    
    id obs = objc_getAssociatedObject(self, kObserver);
    if (obs) {
        /* 调用监听对象实现的方法 */
        objc_msgSend(obs, @selector(observeValueForKeyPath:ofObject:change:context:), keyPath, self, @{@"NSKeyValueObservingOptionNew":obj, @"NSKeyValueObservingOptionOld":oldValue}, nil);
    }
}

- (void)xl_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context  {
    
    /* 保存监听对象 */
    self.observer = observer;
    
    /* 动态创建子类 */
    Class NSObjectKVO = objc_allocateClassPair([self class], "NSObjectKVO", 0);
    
    /* 获取setter方法名 */
    NSString*setterName=[NSString stringWithFormat:@"set%@%@:",[[keyPath substringToIndex:1] uppercaseString],[keyPath substringFromIndex:1]];
    
    /* 为子类动态添加方法 */
    BOOL success = class_addMethod(NSObjectKVO, NSSelectorFromString(setterName), (IMP)setterMethod, "V@:");
    if (success) {
        /* 将当前对象指向新建的子类 */
        object_setClass(self, NSObjectKVO);
    }else{
        
    }
    
}

@end

很简单的实现,demo就不上传github了,放在了CSDN,有兴趣多支持一下。

相关文章

  • iOS 利用runtime手动实现KVO

    KVO原理:调用监听对象属性的方法,动态创建一个继承自该对象所属类的子类,然后重写该属性的setter方法,在se...

  • KVO 的本质?

    iOS 用什么方式实现对一个对象的 KVO ? (KVO 的本质是什么?) 首先利用 Runtime API 动态...

  • ios-Runtime(运行时)

    利用runtime来实现归档解档 方法交换 俗称 OC的方法欺骗 KVO的实现原理 用runtime来实现KVO...

  • iOS_KVO本质解析

    iOS 用什么方式实现对一个对象的KVO?(KVO的本质是什么) 利用Runtime API动态生成一个子类, 并...

  • 【iOS】手动实现KVO+Runtime

    前言 KVO:简单的来说,就是观察者观察被观察对象属性的变化而发生相应的变化。实现的原理基于KVC与强大的Runt...

  • iOS 自定义KVO

    自己实现kvo之前,需要知道iOS系统对kvo的实现。 系统实现kvo的原理 这依赖了OC强大的runtime特性...

  • iOS-底层原理(4)-KVO原理详解

    面试题 1. iOS用什么方式实现对一个对象的KVO?(KVO的本质是什么?) 利用Runtime动态生成一个子类...

  • iOS - KVO

    ios用什么方式实现一个对象的kvo?(kvo的本质是什么?) 1.利用runtime的动态生成一个子类,并且让实...

  • iOS 自定义KVO

    利用Runtime 实现简单的自定义kvo 代码githubgithub.com/zswj/custom-KVO ...

  • iOS KVO 自己实现(利用Runtime)

    一、KVO 实现机制 Apple 的文档有简单提到过 KVO 的实现: 被观察对象的 isa 指针会指向一个中间类...

网友评论

      本文标题:iOS 利用runtime手动实现KVO

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