@interface LGPerson : NSObject
- (void)personInstanceMethod;
+ (void)personClassMethod;
@end
@implementation LGPerson
- (void)personInstanceMethod{
NSLog(@"person对象方法:%s",__func__);
}
+ (void)personClassMethod{
NSLog(@"person类方法:%s",__func__);
}
@end
@interface LGStudent : LGPerson
@end
@implementation LGStudent
@end
@implementation LGStudent (LG)
+ (void)load{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[LGRuntimeTool lg_methodSwizzlingWithClass:self oriSEL:@selector(personInstanceMethod) swizzledSEL:@selector(lg_studentInstanceMethod)];
});
}
//- (void)personInstanceMethod{
// [super personInstanceMethod];
// NSLog(@"person对象方法:%s",__func__);
//}
// personInstanceMethod 我需要父类的这个方法的一些东西
// 给你加一个personInstanceMethod 方法
// imp
- (void)lg_studentInstanceMethod{
[self lg_studentInstanceMethod];
NSLog(@"LGStudent分类添加的lg对象方法:%s",__func__);
}
@interface LGRuntimeTool : NSObject
/**
交换方法
@param cls 交换对象
@param oriSEL 原始方法编号
@param swizzledSEL 交换的方法编号
*/
+ (void)lg_methodSwizzlingWithClass:(Class)cls oriSEL:(SEL)oriSEL swizzledSEL:(SEL)swizzledSEL;
+ (void)lg_betterMethodSwizzlingWithClass:(Class)cls oriSEL:(SEL)oriSEL swizzledSEL:(SEL)swizzledSEL;
@end
@implementation LGRuntimeTool
+ (void)lg_methodSwizzlingWithClass:(Class)cls oriSEL:(SEL)oriSEL swizzledSEL:(SEL)swizzledSEL{
if (!cls) NSLog(@"传入的交换类不能为空");
Method oriMethod = class_getInstanceMethod(cls, oriSEL);
Method swiMethod = class_getInstanceMethod(cls, swizzledSEL);
method_exchangeImplementations(oriMethod, swiMethod);
}
+ (void)lg_betterMethodSwizzlingWithClass:(Class)cls oriSEL:(SEL)oriSEL swizzledSEL:(SEL)swizzledSEL{
if (!cls) NSLog(@"传入的交换类不能为空");
// oriSEL personInstanceMethod
// swizzledSEL lg_studentInstanceMethod
Method oriMethod = class_getInstanceMethod(cls, oriSEL);
Method swiMethod = class_getInstanceMethod(cls, swizzledSEL);
// 尝试添加
BOOL success = class_addMethod(cls, oriSEL, method_getImplementation(swiMethod), method_getTypeEncoding(oriMethod));
/**
personInstanceMethod(sel) - lg_studentInstanceMethod(imp)
lg_studentInstanceMethod (swizzledSEL) - personInstanceMethod(imp)
*/
if (success) {// 自己没有 - 交换 - 没有父类进行处理 (重写一个)
class_replaceMethod(cls, swizzledSEL, method_getImplementation(oriMethod), method_getTypeEncoding(oriMethod));
}else{ // 自己有
method_exchangeImplementations(oriMethod, swiMethod);
}
}
在viewcontroller
执行下面代码
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 黑魔法坑点: 子类没有实现 - 父类实现
LGStudent *s = [[LGStudent alloc] init];
[s personInstanceMethod];
LGPerson *p = [[LGPerson alloc] init];
[p personInstanceMethod];
}
@end
会崩溃:
子类没有实现方法,方法交换交换的是父类的方法imp
,父类并没有lg_studentInstanceMethod
方法,所以崩溃了。
解决方法:
- 子类重新实现一下交换的方法。
- (void)personInstanceMethod{
[super personInstanceMethod];
}
- 交换的方法不重新执行原来的方法,但是这样原来的逻辑就没有了。
- (void)lg_studentInstanceMethod{
// [self lg_studentInstanceMethod];
NSLog(@"LGStudent分类添加的lg对象方法:%s",__func__);
}
lg_betterMethodSwizzlingWithClass
交换判断如果能添加方法,证明子类没有这个方法,我们就添加这个方法,把子类对应的sel和imp交换一下,也实现了方法交换。如果不能添加,证明原来有,直接交换方法。