git下載地址:git@github.com:lu459700780/RunTime.gitgit
viewController.hgithub
#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.matom
#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.hspa
#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