準(zhǔn)備工作
- 重寫(xiě)一個(gè)分類(lèi) 一般是NSObject
- 需要導(dǎo)入一個(gè)頭文件
#import <objc/message.h>
頭文件聲明方法
- (void)rylsj_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;
方法實(shí)現(xiàn)
//self -->被觀察者person
//observer -->觀察者
- (void)rylsj_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context{
/*
1、自定義一個(gè)子類(lèi)
2、重寫(xiě)setName方法,在方法中,調(diào)用super的通知觀察者
3、修改當(dāng)前的isa指針,指向自定義的子類(lèi)
*/
//1.動(dòng)態(tài)生成一個(gè)類(lèi)
//1.1獲取類(lèi)名
NSString *oldClassName = NSStringFromClass([self class]);
NSString *newClassName = [@"RYLSJKVO_" stringByAppendingString:oldClassName];
const char *newName = [newClassName UTF8String];
//創(chuàng)建一個(gè)類(lèi)的class
Class myClass = objc_allocateClassPair([self class], newName, 0);
//注冊(cè)類(lèi)
objc_registerClassPair(myClass);
//2.添加set方法
class_addMethod(myClass, @selector(setName:), (IMP)setName, "v@:@");
//3.修改isa指針
object_setClass(self, myClass);
//4.保存觀察者對(duì)象
objc_setAssociatedObject(self, @"objc", observer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
說(shuō)明
- objc_registerClassPair 這個(gè)方法是重新注冊(cè)了一個(gè)新類(lèi)
- 參數(shù)使用的是char * 的 const char *newName = [newClassName UTF8String]; 這樣可以把OC的字符串轉(zhuǎn)換為char * 類(lèi)型的
方法實(shí)現(xiàn)
void setName(id self,SEL _cmd,NSString *newName){
//NSLog(@"調(diào)用了setName方法!");
//保存子類(lèi)型
id class = [self class];
//改變self的isa指針
object_setClass(self, class_getSuperclass(class));
//調(diào)用父類(lèi)的set方法
objc_msgSend(self, @selector(setName:),newName);
//NSLog(@"修改完畢!");
//拿到觀察者
id objc = objc_getAssociatedObject(self, @"objc");
//通知觀察者
objc_msgSend(objc, @selector(observeValueForKeyPath:ofObject:change:context:),self,@"name",nil,nil);
//改回子類(lèi)類(lèi)型
object_setClass(self, class);
}
說(shuō)明
- 這里是C語(yǔ)言方法
- 這里修改了指針為自定義的對(duì)象
- 需要在setting中 搜索msg把YES設(shè)置為NO
設(shè)置msg為NO