最近在项目中需要对一些对象做isa-swizzling,并且重写掉原始类中的所有setter、getter方法。一开始使用isa-swizzling也挺顺利的,直到遇到了KVO。
众所周知,KVO的实现也是isa-swizzling。所以可能和自定isa-swizzling kennel存在冲突,但是没有找到具体原因。
所以如果有大佬知道该怎么解决,我愿意献上我的膝盖
代码如下:
ViewController
#import "ViewController.h"
#import "NSObject+Hook.h"
@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
@end
@implementation Person
@end
@interface ViewController ()
@property (nonatomic, strong) Person *person;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
/// 对象先做一次KVO
/// 然后对KVO后的对象在做一次 isa-swizzling
/// 这时候修改name,KVO会崩溃
[self.person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];
[self.person hook:@selector(setTip:)];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.person.name = @"123";
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
NSLog(@"%@", change);
}
- (Person *)person
{
if (!_person) {
_person = [[Person alloc] init];
}
return _person;
}
@end
NSObject+Hook
#import "NSObject+Hook.h"
#import <objc/runtime.h>
#import <objc/message.h>
@implementation NSObject (Hook)
- (void)hook:(SEL)cmd
{
Class class = object_getClass(self);
NSString *subClassName = [NSString stringWithFormat:@"HOOK_%@", NSStringFromClass(class)];
Class subClass = objc_allocateClassPair(class, subClassName.UTF8String, 0);
objc_registerClassPair(subClass);
object_setClass(self, subClass);
Method method = class_getInstanceMethod(subClass, cmd);
class_addMethod(subClass, cmd, (IMP)setterMethod, method_getTypeEncoding(method));
}
void setterMethod(id self, SEL _cmd, id obj)
{
struct objc_super superClass = {
self,
class_getSuperclass(object_getClass(self))
};
objc_msgSendSuper(&superClass, _cmd, obj);
}
@end
运行崩溃如下图:
git仓库: