原文地址:runtime 方法替换 和 动态添加类方法 结合使用 这个也是我自己写的哦,实现了我自己的想法
前言:方法替换,可以替换任意外部类的方法,而动态添加方法只能实现在被添加类创建的对象里,但是将方法替换和动态添加方法结合使用,可以实现,对任意外部类动态添加需要的方法,这个方法可以是类方法也可以是实例方法。
缺陷:1、含参数的方法难以处理,参数值需要根据实际业务逻辑而定。
Create Person.h and Person.m
Person.h:
1 2 3 4 5
| #import <Foundation/Foundation.h>
@interface Person : NSObject
@end
|
Person.m:
1 2 3 4 5
| #import "Person.h"
@implementation Person
@end
|
Create OtherPerson.h and OtherPerson.m
OtherPerson.h:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| // // Created by HEYANG on 16/1/11. // Copyright © 2016年 HEYANG. All rights reserved. //
#import "OtherPerson.h" #import <objc/message.h>
@implementation OtherPerson
+(void)load{ Class clazz = NSClassFromString(@"Person"); //获取替换前的类方法 Method instance_eat = class_getClassMethod(clazz, @selector(resolveInstanceMethod:)); //获取替换后的类方法 Method instance_notEat = class_getClassMethod(self, @selector(hy_resolveInstanceMethod:)); //然后交换类方法 method_exchangeImplementations(instance_eat, instance_notEat); //获取替换前的类方法 Method class_eat = class_getClassMethod(clazz, @selector(resolveClassMethod:)); //获取替换后的类方法 Method class_notEat = class_getClassMethod(self, @selector(hy2_resolveClassMethod:)); //然后交换类方法 method_exchangeImplementations(class_eat, class_notEat); }
void eat_1(id self,SEL sel) { NSLog(@"到底吃不吃饭了"); NSLog(@"%@ %@",self,NSStringFromSelector(sel)); } void eat_2(id self,SEL sel, NSString* str1,NSString* str2) { NSLog(@"到底吃不吃饭了"); NSLog(@"%@ %@",self,NSStringFromSelector(sel)); NSLog(@"打印两个参数值:%@ and %@",str1,str2); }
+(BOOL)hy_resolveInstanceMethod:(SEL)sel{ //当sel为实现方法中 有 eat 方法 if (sel == NSSelectorFromString(@"eat")) { //就 动态添加eat方法 // 第一个参数:给哪个类添加方法 // 第二个参数:添加方法的方法编号 // 第三个参数:添加方法的函数实现(函数地址) // 第四个参数:函数的类型,(返回值+参数类型) v:void @:对象->self :表示SEL->_cmd class_addMethod(self, sel, (IMP)eat_1, "v@:"); } return YES; } +(BOOL)hy2_resolveClassMethod:(SEL)sel{ if (sel == NSSelectorFromString(@"eat:with:")) { class_addMethod(objc_getMetaClass("Person"), sel, (IMP)eat_2, "v#:@@"); } return YES; }
@end
|
last In file ‘main.m’:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| /** * * Swap Method and Dynamic add Method (交换方法和动态添加方法) * */ #import <Foundation/Foundation.h>
//ignore undeclared warm 忽视未声明的警告 #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wundeclared-selector"
int main(int argc, const char * argv[]) { @autoreleasepool { //get this Person class 拿到了这个Person类 Class clazz = NSClassFromString(@"Person"); //get this Person Instance 拿到这个Person实例 id person = [[clazz alloc] init]; //send message to 'eat' method in Person Class or Person Instance //发送消息给Person类或者Person实例的‘eat’方法 不含参数 [person performSelector:@selector(eat) withObject:nil]; //发送消息给Person类的‘eat’方法 含两个参数 [clazz performSelector:@selector(eat:with:) withObject:@"Hello" withObject:@"World"]; } return 0; }
#pragma clang diagnostic pop
|
the code test result
images/loading.gif' data-original="http://img.hoop8.com/attachments/1601/7953664451394.png" />
download
download github code source
Note
Before use import <objc/message.h>
,need following:
原标题:runtime 方法替换 和 动态添加类方法 结合使用
关键词: