iOS开发runtime实现KVO

利用运行时自定义KVO

//根据keypath 获取set方法
-(SEL)getNewSelector:(NSString *)selectorName
{
    NSString *firstChar = [selectorName substringToIndex:1];
    NSString *upFirst = [firstChar uppercaseString];
    NSString *otherChar = [selectorName substringFromIndex:1];
    NSString *newSelectorName = [NSString stringWithFormat:@"set%@%@:",upFirst,otherChar];
    return  NSSelectorFromString(newSelectorName);
}
//根据set方法 获取keypath
-(NSString *)getKeypath:(SEL)selector
{
    NSString *selectorName = NSStringFromSelector(selector);
    selectorName = [selectorName substringFromIndex:3];
    NSString *firstChar = [selectorName substringToIndex:1];
    NSString *lowFirst = [firstChar lowercaseString];
    NSString *otherChar = [selectorName substringFromIndex:1];
    
    NSString *newChar = [NSString stringWithFormat:@"%@%@",lowFirst,otherChar];
    return  [newChar substringToIndex:newChar.length-1];
}
复制代码

开始监听

-(void)shine_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath
{
    // 1.动态生成一个派生类
    static Class newClass;
    static dispatch_once_t predicate;
    dispatch_once(&predicate, ^{
        NSString * oldClassName = NSStringFromClass([self class]);
        NSString *newClassName = [NSString stringWithFormat:@"Shine_%@",oldClassName];
        //创建派生类
        newClass = objc_allocateClassPair([self class], [newClassName UTF8String], 0);
        //注册派生类
        objc_registerClassPair(newClass);
        //修改被观察者的isa指针,指向自定义的类
        object_setClass(self, newClass);
        //动态绑定
        objc_setAssociatedObject(self, &Shine_KVO, observer, OBJC_ASSOCIATION_ASSIGN);
    });
    //2.生成新的set方法
    SEL selector = [self getNewSelector:keyPath];
    //3.添加新的set方法
    class_addMethod(newClass, selector, (IMP)setObj, "v@:@");
    
}
复制代码

属性更改回调

void setObj(id sf,SEL cd,id value){
    NSString *keypath = [sf getKeypath:cd];
    id oldValue = [sf valueForKey:keypath];
    NSMutableDictionary *change = @{}.mutableCopy;
    if (oldValue != nil) {
        change[@"old"] = oldValue;
    }
    if (value != nil) {
        change[@"new"] = value;
    }
    //取出当前类
    id class = [sf class];
    //指向父类
    object_setClass(sf, class_getSuperclass(class));
    //向父类发送消息
    objc_msgSend(sf, cd ,value);
    //获取动态绑定对象
    id observe = objc_getAssociatedObject(sf, &Shine_KVO);
    //监听回调
    objc_msgSend(observe, @selector(shine_observeValueForKeyPath:ofObject:change:),keypath,sf,change);
    //修改指向
    object_setClass(sf, class);
}
复制代码
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值