ios-runtime

git下载地址:git@github.com:lu459700780/RunTime.git

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
", 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
原文地址:https://www.cnblogs.com/sayimba/p/6289393.html