ios-runtime
viewController.h
#import <UIKit/UIKit.h> @interface ViewController : UIViewController @property(nonatomic,strong)NSString *hello; @property(nonatomic,strong)NSString *hello1; /** * 交换方法使用 */ - (void)method1; - (void)method2; @end
viewController.m
#import "ViewController.h" #import "RunTime.h" #import "RunTime+Category.h" //项目下载地址:git@github.com:lu459700780/RunTime.git @interface ViewController () @end @implementation ViewController -(NSString *)description{ return [NSString stringWithFormat:@"hello:%@",_hello]; } - (instancetype)init { self = [super init]; if (self) { _hello = @"hello"; } return self; } - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor whiteColor]; _hello = @"hello"; //获取某一个类所有属性和所有方法 [RunTime getAllPropertyAndAllMethod:[ViewController class]]; //改变某一属性值 [RunTime changeVariable]; //增加新方法 [RunTime addNewMethod]; //交换方法 [RunTime exchangeMethod]; //增加新属性 RunTime *keytool = [[RunTime alloc]init]; keytool.newVariable = @"Hello"; keytool.height = 100; NSLog(@"%@",[keytool newVariable]); NSLog(@"%f",[keytool height]); } - (void)method1 { NSLog(@"method1"); } - (void)method2 { NSLog(@"method2"); } @end
RunTime.h
#import <Foundation/Foundation.h> #import <UIKit/UIKit.h> @interface RunTime : NSObject /** * 获取所有成员变量和方法 * * @param myClass 类别 */ + (void)getAllPropertyAndAllMethod:(id)myClass; /** * 改变属性值 */ + (void)changeVariable; /** * 增加新方法 */ + (void)addNewMethod; /** * 交换方法 */ + (void)exchangeMethod; @end
RunTime.m
#import "RunTime.h" #import <objc/runtime.h> #import "ViewController.h" //获取屏幕宽度的宏 #define ScreenWidth ([[UIScreen mainScreen] bounds].size.width) @implementation RunTime + (void)getAllPropertyAndAllMethod:(id)myClass { unsigned int outCount = 0; // 获取到所有的成员变量列表 Ivar *vars = class_copyIvarList([myClass class], &outCount); // 遍历所有的成员变量 for (int i = 0; i < outCount; i++) { Ivar ivar = vars[i]; // 取出第i个位置的成员变量 const char *propertyName = ivar_getName(ivar); // 获取变量名 const char *propertyType = ivar_getTypeEncoding(ivar); // 获取变量编码类型 printf("变量名%s/变量编码类型%s\n", propertyName, propertyType); } unsigned int count; //获取方法列表,所有在.m文件显式实现的方法都会被找到,包括setter+getter方法; Method *allMethods = class_copyMethodList([myClass class], &count); for(int i =0;i<count;i++) { //Method,为runtime声明的一个宏,表示对一个方法的描述 Method md = allMethods[i]; //获取SEL:SEL类型,即获取方法选择器@selector() SEL sel = method_getName(md); //得到sel的方法名:以字符串格式获取sel的name,也即@selector()中的方法名称 const char *methodname = sel_getName(sel); NSLog(@"(Method:%s)",methodname); } } + (void)changeVariable { ViewController *viewVC = [[ViewController alloc]init]; NSLog(@"改变前的viewVC里面的属性:%@",viewVC); unsigned int count = 0; Ivar *vars = class_copyIvarList([ViewController class], &count); Ivar ivv = vars[0]; //从第一个方法getAllVariable中输出的控制台信息,我们可以看到实例属性。 object_setIvar(viewVC, ivv, @"world"); //属性被强制改为world。 NSLog(@"改变之后的viewVC里面的属性:%@",viewVC); } + (void)addNewMethod { /* 动态添加方法: 第一个参数表示Class cls 类型; 第二个参数表示待调用的方法名称; 第三个参数(IMP)addingMethod,IMP一个函数指针,这里表示指定具体实现方法addingMethod; 第四个参数表方法的参数,0代表没有参数; */ Method newMethod = class_getInstanceMethod(self, @selector(myNewMethod)); ViewController *viewVC = [[ViewController alloc]init]; class_addMethod([viewVC class], @selector(myNewMethod), method_getImplementation(newMethod), method_getTypeEncoding(newMethod)); //调用方法 [viewVC performSelector:@selector(myNewMethod) withObject:nil]; } - (void)myNewMethod { NSLog(@"addNewMethod"); } //具体的实现(方法的内部都默认包含两个参数Class类和SEL方法,被称为隐式参数。) int addingMethod(id self, SEL _cmd){ NSLog(@"已新增方法:myNewMethod"); return 1; } + (void)exchangeMethod { ViewController *viewVC = [[ViewController alloc]init]; Method method1 = class_getInstanceMethod([viewVC class], @selector(method1)); Method method2 = class_getInstanceMethod([viewVC class], @selector(method2)); //交换方法 method_exchangeImplementations(method1, method2); [viewVC method1]; } @end
RunTime+Category.h
#import "RunTime.h" @interface RunTime (Category) /** * 增加属性(字符串类型) */ @property (nonatomic,strong)NSString *newVariable; /** * 增加属性(常量) */ @property (nonatomic,assign)float height; @end
RunTime+Category.m
#import "RunTime+Category.h" #import <objc/runtime.h> //runtime API的使用需要包含此头文件 //增加多个属性,key值不能一样 const char * keytool = "keytool"; //做为key,字符常量 必须是C语言字符串; const char * keytool2 = "keytool2"; //做为key,字符常量 必须是C语言字符串; @implementation RunTime (Category) /** * 添加新属性 * * @param newVariable 新属性名 */ -(void)setNewVariable:(NSString *)newVariable{ NSString *newStr = [NSString stringWithFormat:@"%@",newVariable]; /* 第一个参数是需要添加属性的对象; 第二个参数是属性的key; 第三个参数是属性的值; 第四个参数是一个枚举值,类似@property属性创建时设置的关键字,可从命名看出各含义 */ objc_setAssociatedObject([RunTime class],keytool, newStr, OBJC_ASSOCIATION_COPY_NONATOMIC); } /** * 提取属性的值 * * @return 属性值 */ -(NSString *)newVariable{ NSString *myNewVariable = objc_getAssociatedObject([RunTime class], keytool); return myNewVariable; } /** * 添加新属性 * * @param height 新属性名 */ -(void)setHeight:(float)height{ NSNumber *num = [NSNumber numberWithFloat:height]; /* 第一个参数是需要添加属性的对象; 第二个参数是属性的key; 第三个参数是属性的值; 第四个参数是一个枚举值,类似@property属性创建时设置的关键字,可从命名看出各含义 */ objc_setAssociatedObject([RunTime class],keytool2, num, OBJC_ASSOCIATION_COPY_NONATOMIC); } /** * 提取属性的值 * * @return 属性值 */ -(float)height{ NSNumber *number = objc_getAssociatedObject([RunTime class], keytool2); return [number floatValue]; } @end