首页 > 代码库 > runtime基础

runtime基础

//
//  ViewController.m
//  RunTime
//
//  Created by mac on 2017/4/26.
//  Copyright ? 2017年 cqytjrcqytjr. All rights reserved.
//

#import "ViewController.h"

#import <objc/runtime.h>


#import <objc/message.h>
@interface ViewController ()<UITableViewDataSource>{
    NSArray *_property0;
    NSArray *property1;
}
@property (nonatomic,strong)UIColor *property2;

@property (nonatomic,strong)NSArray *property0;
@end

@implementation ViewController



- (void)viewDidLoad {
    [super viewDidLoad];
    
//    [self getAndSet];
//    [self objectGetMethod];
//    [self getClassCopy];
    [self method0];
    
    
    BOOL result0 = class_replaceMethod([self class], @selector(method0), [ViewController instanceMethodForSelector:NSSelectorFromString(@"method1")], NULL);
    NSLog(@">>>>>>>>2:%@",@(result0));
    [self method0];
    
}


-(void)getAndSet{
    //添加--为动态创建类添加变量
    /**
     * 1.只能给动态创建的类添加变量也就是用 objc_allocateClassPair 创建的类
     * 2.添加变量只能在函数 objc_allocateClassPair 和 class_getInstanceVariable 之间添加才有效
     */
    Class CreatClass0 = objc_allocateClassPair([NSObject class], "CreatClass0", 0);
    class_addIvar(CreatClass0, "_attribute0", sizeof(NSString *), log(sizeof(NSString *)), "i");

    Ivar ivar = class_getInstanceVariable(CreatClass0, "_attribute0");//获取变量,如果没获取到说明不存在
    NSLog(@">>>>>>>>0:%@",[NSString stringWithUTF8String:ivar_getName(ivar)]);
    objc_registerClassPair(CreatClass0);
    NSLog(@"\n");
    
    
    //添加--为动态创建的类添加变量然后添加属性,类和变量和属性都是动态创建的
    /**
     * 1.各个属性:暂时不知道
     * 2.下面这个反驳了上面的第二标,这个证明id不是不会报错,规律是如果id调用的是系统的类的方法,那么就不会报错,
     详细介绍:上面的@selector(name) 和 @selector(setName:) name是好多系统类都有方法,所以id会认为本身代表的是那个类
     所以不会报错,但是如果你硬写一个完全没有的方法,它就会报错
     * 3.添加属性不用再objc_registerClassPair之前,因为添加属性其实就是添加变量的set 和 get方法而已
     * 4.添加的属性和变量不能用kvc设置值和取值
     */
    
    objc_property_attribute_t type2 = { "T", "@\"NSString\"" };//"T"表示获取该属性的类型
    //  objc_property_attribute_t attribute2 = {"N",""};//value无意义时通常设置为空
    objc_property_attribute_t ownership2 = { "C", "" }; // C = copy
    objc_property_attribute_t backingivar2  = { "V", "_attribute0" };//


    objc_property_attribute_t attrs2[] = { type2, ownership2, backingivar2 };
    class_addProperty(CreatClass0, "_attribute0", attrs2, 3);
    
    SEL getter = NSSelectorFromString(@"attribute0");
    SEL setter = NSSelectorFromString(@"setAttribute0:");
    BOOL suc0 = class_addMethod(CreatClass0, getter, (IMP)attribute0Getter, "@@:");//i@:@ i:返回值类型int,若是v则表示void
    BOOL suc1 = class_addMethod(CreatClass0, setter, (IMP)attribute0Setter, "v@:@");//i@:@
    NSLog(@">>>>>>>>3:%@:%@",@(suc0),@(suc1));
    id idclass = [[CreatClass0 alloc]init];
    NSLog(@">>>>>>>>1:%@",[idclass performSelector:getter withObject:nil]);//withObject 传递的参数
    [idclass performSelector:setter withObject:@"为动态创建类先添加变量再添加属性"];
    NSLog(@">>>>>>>>2:%@",[idclass performSelector:getter withObject:nil]);
    //class获取--获取整个类的实例方法的方法列表
    /**
     *  1.获取所有实例方法,不包含静态方法
     *  2.不获取父类的方法
     *  3.隐式的get set 方法也能获取到
     *  4.关于Method的更多用法参考Class2类
     */
    unsigned int copycopyMethodListCount = 0;
    Method *methods = class_copyMethodList([self class], &copycopyMethodListCount);
    for (NSInteger i = 0; i < copycopyMethodListCount; i++) {
        Method method = methods[i];
        SEL name = method_getName(method);
//        NSLog(@">>>>>>>>2:copyMethodList:%@",NSStringFromSelector(name));
    }
    free(methods);//释放
    NSLog(@"\n");
    
    BOOL result0 = class_addProtocol([self class], NSProtocolFromString(@"UITableViewDelegate"));
    NSLog(@">>>>>>>>3:添加协议成功");
    //添加--协议
    /**
     * 1.class_addProtocol  参数含义:第一个:要添加协议的类,第二个:协议对象
     * 2.获取协议列表具体细节参照Class1里的内容
     */
    unsigned int copyProtocolListCount = 0;
    Protocol * __unsafe_unretained *protocals = class_copyProtocolList([self class], &copyProtocolListCount);
    for (NSInteger i = 0; i < copyProtocolListCount; i++) {
        Protocol * protocal = protocals[i];
        const char *name = protocol_getName(protocal);
        NSLog(@">>>>>>>>4:copyProtocolList:%s",name);
    }
    free(protocals);//释放
    NSLog(@"\n");
}
//get方法
NSString *attribute0Getter(id classInstance, SEL _cmd) {
    
    
    NSLog(@"%@    %@",classInstance,NSStringFromSelector(_cmd));
    Ivar ivar = class_getInstanceVariable([classInstance class], "_attribute0");//获取变量,如果没获取到说明不存在
    return object_getIvar(classInstance, ivar);
}

//set方法
void attribute0Setter(id classInstance, SEL _cmd, NSString *newName) {
    Ivar ivar = class_getInstanceVariable([classInstance class], "_attribute0");//获取变量,如果没获取到说明不存在
    id oldName = object_getIvar(classInstance, ivar);
    if (oldName != newName) object_setIvar(classInstance, ivar, [newName copy]);
}




-(void)getClassCopy{
    
    //class获取--获取整个成员变量列表
    /**
     *  1.获取所有私有变量和属性
     *  2.获取的私有变量的名和定义的名一模一样
     *  3.获取的属性的名前面都添加了下划线
     */
    unsigned int copyIvarListCount = 0;

    Ivar *ivars = class_copyIvarList([self class], &copyIvarListCount);
    for (NSInteger i = 0; i< copyIvarListCount; i ++) {
        
        Ivar ivar = ivars[i];
        const char *name = ivar_getName(ivar);
        NSLog(@">>>>>>>>0:class_copyIvarList:%s",name);
        
        
        
        
    }
    free(ivars);//释放
    NSLog(@"\n");
    
    
    //获取属性列表(只获取属性不获取变量)
    //入参:类Class,int变量指针
    //返回:属性信息objc_property_t列表
    //*  1.获取所有属性
    //*  2.获取的属性名和你代码写的一样,获取出来的属性名不自动添加下划线
    //*  3.不能获取Category添加的属性。
    
    unsigned int property = 0;
    objc_property_t *objcProperty = class_copyPropertyList([self class], &property);
    for (NSInteger i = 0; i < property; i++) {
        objc_property_t propertyT = objcProperty[i];
        const char *name = property_getName(propertyT);
        NSLog(@">>>>>>>>0:class_copyIvarList:%s",name);
    }
    
    free(objcProperty);
    NSLog(@"\n");
    

    //获取方法列表
    //入参:类Class,int变量指针
    //返回:方法信息Method列表
    //*  1.获取所有实例方法,不包含静态方法
    //*  2.不获取父类的方法
    //*  3.隐式的get set 方法也能获取到
    //*  4.可以获取分类和动态添加的方法。
//    Method *class_copyMethodList(Class cls, unsigned int *outCount)
    
    unsigned int methodCount = 0;
    Method *methods = class_copyMethodList([self class], &methodCount);
    for(NSInteger i = 0 ; i < methodCount; i++){
        Method thod = methods[i];
        SEL name = method_getName(thod);
        NSLog(@"***:%@",NSStringFromSelector(name));
        ;
        
    }
    
    free(methods);
    
    NSLog(@"\n");
    //添加--协议
    /**
     * 1.class_addProtocol  参数含义:第一个:要添加协议的类,第二个:协议对象
     * 2.获取协议列表具体细节参照Class1里的内容
     */
    unsigned int copyProtocolListCount = 0;
    Protocol * __unsafe_unretained *protocals = class_copyProtocolList([self class], &copyProtocolListCount);
    for (NSInteger i = 0; i < copyProtocolListCount; i++) {
        Protocol * protocal = protocals[i];
        const char *name = protocol_getName(protocal);
        NSLog(@">>>>>>>>3:copyProtocolList:%s",name);
    }
    free(protocals);//释放
    NSLog(@"\n");
    
    
    
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return 0;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    return nil;
}
/*
 
 SEL:类成员方法的指针,但不同于C语言中的函数指针,函数指针直接保存了方法的地址,但SEL只是方法编号。
 IMP:一个函数指针,保存了方法的地址
 Method:方法的结构体,其中保存了方法的名字,实现和类型描述字符串
 
 //在runtime.h里面我们可以看到定义
 //Method 是一个方法结构体的指针
 typedef struct objc_method *Method;
 //方法的结构体包含了方法需要的信息
 struct objc_method {
   SEL method_name;
   char *method_types;//方法返回值,和各个参数类型等的字符串描述
   IMP method_imp;
 }
 //根据函数获取函数的SEL
 @selector()
 //获取函数指针SEL的函数名字符串
 NSString *NSStringFromSelector(SEL aSelector);
 //根据函数名获取函数指针
 SEL NSSelectorFromString(NSString *aSelectorName);
 //获取类Class的字符串描述
 NSString *NSStringFromClass(Class aClass);
 //根据类的字符串描述获取类Class
 Class _Nullable NSClassFromString(NSString *aClassName);
 //获取协议的字符串描述(协议名字)
 NSString *NSStringFromProtocol(Protocol *proto)
 //根据协议名字获取协议对象
 Protocol * _Nullable NSProtocolFromString(NSString *namestr)
 
 
 
 */

#pragma mark objectGetMethod
-(void)objectGetMethod{
    //获取类名
    //入参:类Class
    //返回:类名char数组
    const char *result0 = class_getName([ViewController class]);
    NSLog(@">>>>>>>>0:%@",[NSString stringWithUTF8String:result0]);
    
    //获取父类
    //入参:类Class
    //返回:类Class
    Class result1 = class_getSuperclass([ViewController class]);
    NSLog(@">>>>>>>>1:%@",result1);
    
    //获取实例大小(返回size_t)
    //入参:实例的类Class
    //返回:大小size_t
    //深究请看这篇文章http://www.jianshu.com/p/df6b252fbaae
    size_t result2 = class_getInstanceSize([ViewController class]);
    NSLog(@">>>>>>>>2:%zu",result2);
    
    //获取类中指定名称实例成员变量的信息
    //入参:类Class,变量名
    //返回:变量信息Ivar
    //* 1.实例变量是指变量不是属性.例如某类有个属性为:username 那么它对应的实例变量为_username
    //* 2.这个方法可以获取属性的变量,也可以获取私有变量(这点很重要)
    //* 3.如果获取的变量为空,那么 ivar_getName和 ivar_getTypeEncoding 获取的值为空,那么[NSString stringWithUTF8String:ivar1Name] 执行崩溃
    const char *result3 = [@"property0" UTF8String];
    Ivar result4 = class_getInstanceVariable([ViewController class], result3);
    NSLog(@">>>>>>>>3:%@",result4);
    
    //获取指定的属性
    //入参:类Class,属性名char数组
    //返回:属性objc_property_t
    // *  1.属性不是变量,此方法只能获取属性
    // *  2.如果属性不存在那么返回的结构体为0(可以参考下面的判断)
    // *  3.属性不存在获取property_getName 和 property_getAttributes 会崩溃
    const char *result5 = [@"property0" UTF8String];
    objc_property_t result6 = class_getProperty([ViewController class], result5);
    NSLog(@">>>>>>>>4:%@",[NSString stringWithUTF8String:property_getName(result6)]);
    
    //获取方法实现
    //入参:类Class,方法名SEL
    //返回:方法实现IMP
    IMP result7 = class_getMethodImplementation([ViewController class], @selector(method0));
    result7();
    
    //获取方法实现
    //入参:类Class,方法名SEL
    //返回:方法实现IMP
    IMP result8 = class_getMethodImplementation_stret([ViewController class], @selector(method1));
    result8();
    
    //获取类方法
    //入参:类Class,方法名SEL
    //返回:方法Method
    Method result9 = class_getClassMethod([ViewController class], @selector(viewDidLoad));
    NSLog(@">>>>>>>>7:%@",result9);
}
-(void)method0{
    NSLog(@">>>>>>>>5");
}
-(void)method1{
    NSLog(@">>>>>>>>6");
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

 

runtime基础