欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

[求助]新人关于KVO问题请教,谢谢大家

程序员文章站 2022-04-13 15:33:30
...

最近研究runtime,在网上看到一个大神写的runtime手动实现KVO,自己试了试
但是却出现一些问题,想求助各位大神 新人第一次发帖。


结构:

  • 在ViewController中监听people(继承自NSobject)类的name。
  • 监听类NSObject (KVO),具体的监听实现。

方法:
* people类:

#import <Foundation/Foundation.h>

@interface people : NSObject

@property(nonatomic,copy)NSString *name;

@end
  • NSObject (KVO)
#import <Foundation/Foundation.h>

@interface NSObject (KVO)

-(void)PE_addobserve:(NSObject *)observer forkeyPath:(NSString *)keypath options:(NSKeyValueObservingOptions)options context:(void *)context;
@end

具体实现

#import "NSObject+KVO.h"

#import <objc/runtime.h>

#import <objc/message.h>


@implementation NSObject (KVO)


-(void)PE_addobserve:(NSObject *)observer forkeyPath:(NSString *)keypath options:(NSKeyValueObservingOptions)options context:(void *)context
{

    //保存observer
    objc_setAssociatedObject(self, (__bridge const void*)@"objc", observer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);


    //动态生成新的对象
    NSString *oldstring=NSStringFromClass([self class]);

    NSString *newString=[@"PE_" stringByAppendingString:oldstring];

    const char* newname=[newString UTF8String];

    //注册新类,添加方法
    Class newclass=objc_allocateClassPair([self class], newname, 0);

    class_addMethod(newclass, @selector(setName:),(IMP)setName,"aaa@qq.com:@");

    objc_registerClassPair(newclass);

    object_setClass(self, newclass);


}

//set 方法的重写
void setName(id self,SEL _cmd,NSString* name)
{

    //保存自己类
    Class myclass=[self class];

    //self指向父类
    object_setClass(self,class_getSuperclass([self class]));

//    struct objc_super sup;
//
//    sup.receiver=myclass;
//
//    sup.super_class=class_getSuperclass([self class]);

    //父类执行方法
    objc_msgSend(self,@selector(setName:),name);

    //获取observer对象
    id objc= objc_getAssociatedObject(self, (__bridge const void*)@"objc");

    //通知observer执行方法
    objc_msgSend(objc, @selector(addObserver:forKeyPath:options:context:),self,name,NSKeyValueObservingOptionNew,nil);

    //self指回来
    object_setClass(self, myclass);

}

*VC中的处理

- (void)viewDidLoad {
    [super viewDidLoad];

    self.pe=[[people alloc]init];

//    self.pe.name=[[NSString alloc]init];

    [self.pe setValue:@"黄龙" forKeyPath:@"name"];

    [self.pe PE_addobserve:self forkeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];

    UIButton *btn =[UIButton buttonWithType:UIButtonTypeCustom];

    btn.frame=CGRectMake(100,100, 200, 100);

    btn.backgroundColor=[UIColor brownColor];

    [btn addTarget:self action:@selector(btnclick) forControlEvents:UIControlEventTouchUpInside];

    [self.view addSubview:btn];

//    [self addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];


    // Do any additional setup after loading the view, typically from a nib.
}

-(void)btnclick
{
    self.pe.nameaaa@qq.com"小黄狗";
//    [self.pe setValue:@"小黄狗" forKeyPath:@"name"];
}


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

{

    NSLog(@"我可能要换个名字了:%@",[self.pe valueForKeyPath:@"name"]);

}

但是当我点击按钮的的时候却爆出内存错误:

[求助]新人关于KVO问题请教,谢谢大家

我尝试将people中的name的属性改为strong,只是一种尝试

@property(nonatomic,strong)NSString *name;

依然出现内存错误:

[求助]新人关于KVO问题请教,谢谢大家

第二张图片截图的时候不小心在方法中加了4,报错未实现警告,但是不影响

尝试初始化依然不行

小白有点麻爪求助

附上源码地址 :源码