Recently, I studied runtime. I saw a great God written runtime on the Internet to manually implement KVO. I tried it myself
But there are some problems. I want to ask you to post for the first time.
Structure:
- Listen for the name of the people (inherited from the NSobject) class in the ViewController.
- Monitor class NSObject (KVO), specific monitor implementation.
Method:
*people class:
#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
Concrete realization
#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
{
//Save observer
objc_setAssociatedObject(self, (__bridge const void*)@"objc", observer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
//Dynamically generate new objects
NSString *oldstring=NSStringFromClass([self class]);
NSString *newString=[@"PE_" stringByAppendingString:oldstring];
const char* newname=[newString UTF8String];
//Register new class, add method
Class newclass=objc_allocateClassPair([self class], newname, 0);
class_addMethod(newclass, @selector(setName:),(IMP)setName,"v@:@");
objc_registerClassPair(newclass);
object_setClass(self, newclass);
}
//Rewrite of set method
void setName(id self,SEL _cmd,NSString* name)
{
//Save your own class
Class myclass=[self class];
//self points to the parent class
object_setClass(self,class_getSuperclass([self class]));
// struct objc_super sup;
//
// sup.receiver=myclass;
//
// sup.super_class=class_getSuperclass([self class]);
//Parent class execution method
objc_msgSend(self,@selector(setName:),name);
//Get observer object
id objc= objc_getAssociatedObject(self, (__bridge const void*)@"objc");
//Inform observer of execution method
objc_msgSend(objc, @selector(addObserver:forKeyPath:options:context:),self,name,NSKeyValueObservingOptionNew,nil);
//self points back
object_setClass(self, myclass);
}
*Treatment in VC
- (void)viewDidLoad {
[super viewDidLoad];
self.pe=[[people alloc]init];
// self.pe.name=[[NSString alloc]init];
[self.pe setValue:@"Huanglong" 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.name=@"Little yellow dog";
// [self.pe setValue: @ "little yellow dog" forKeyPath:@"name"];
}
-(void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context
{
NSLog(@"I may have to change my name:%@",[self.pe valueForKeyPath:@"name"]);
}
But when I click the button, there is a memory error:
I try to change the attribute of name in people to strong. It's just an attempt
@property(nonatomic,strong)NSString *name;
Memory error persists:
When the second picture is screenshot, 4 is added to the method accidentally. The error is reported and the warning is not implemented, but it does not affect
Attempt to initialize is still not good
Xiaobai has a little claw for help
Attach source address: Source code