美文网首页ios 知识点IOSiOS程序猿
iOS runtime(二)runtime之Ivar 详尽

iOS runtime(二)runtime之Ivar 详尽

作者: 奔跑吧小蚂蚁 | 来源:发表于2018-05-25 17:05 被阅读53次

    runtime官方文章学习大纲

    1.获取成员变量列表

    1.1相关函数

    Ivar可以看出也是一个变量类型
    typedef struct objc_ivar *Ivar;
    //获取成员变量列表
    Ivar *class_copyIvarList(Class cls, unsigned int * outCount) 
    //获取成员变量类型编码
    const char *ivar_getTypeEncoding(Ivar  v) 
    //获取成员变量名称
    const char *ivar_getName(Ivar  v) 
    
    

    1.2实例代码

    #import "ViewController.h"
    #import <objc/runtime.h>
    
    @interface ViewController ()
    
    @property (nonatomic,strong)NSString *name;
    @property (nonatomic,assign)NSString *age;
    @property (nonatomic,strong)NSString *address;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        [self class_copyIvarList];
    }
    
    - (void)class_copyIvarList{
        uint count;
        Ivar *ivars = class_copyIvarList([self class], &count);
        for (unsigned int i = 0; i < count; i ++) {
            Ivar ivar = ivars[i];
            //获取成员变量名称
            NSString* name = @(ivar_getName(ivar));
            //获取成员变量数据类型
            NSString * type = @(ivar_getTypeEncoding(ivar));
            NSLog(@"类型为 %@ 的 %@ ",type, name);
        }
        free(ivars);
    }
    
    

    1.3打印数据

    2018-05-26 10:02:36.597199+0700 runTimer[6417:1017717] 类型为 @"NSString" 的 _name 
    2018-05-26 10:02:36.597586+0700 runTimer[6417:1017717] 类型为 @"NSString" 的 _age 
    2018-05-26 10:02:36.597852+0700 runTimer[6417:1017717] 类型为 @"NSString" 的 _address 
    

    1.4查漏补缺

     //通过变量名称获取类中的实例成员变量
     Ivar class_getInstanceVariable(Class cls, const char * name)
    
    

    实例代码及打印数据:

    #import "ViewController.h"
    #import <objc/runtime.h>
    
    @interface ViewController ()
    
    @property (nonatomic,strong)NSString *name;
    @property (nonatomic,assign)NSString *age;
    @property (nonatomic,strong)NSString *address;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        [self class_getInstanceVariable];
    }
    
    - (void)class_getInstanceVariable{
        //注意成员变量必须“_名称”
        Ivar name_Ivar = class_getInstanceVariable([self class], "_name");
        NSString * name_type = @(ivar_getTypeEncoding(name_Ivar));
        NSString *name_str = @(ivar_getName(name_Ivar));
        NSLog(@"name_type:%@",name_type);
        NSLog(@"name_str:%@",name_str);
    }
    打印数据:
    2018-05-26 10:41:17.384676+0700 runTimer[7091:1043835] name_type:@"NSString"
    2018-05-26 10:41:17.384831+0700 runTimer[7091:1043835] name_str:_name
    

    2.添加成员变量

    2.1相关函数

    //为元类添加成员变量
    BOOL class_addIvar(Class cls, const char * name, size_t size, 
                  uint8_t alignment, const char * types) 
    //添加类 superclass 类是父类   name 类的名字  size_t 类占的空间
    Class objc_allocateClassPair(Class superclass, const char * name,size_t extraBytes) 
    //注册类
    void objc_registerClassPair(Class  cls) 
    //销毁类
    void objc_disposeClassPair(Class _Nonnull cls) 
    

    2.2实例代码

    1. People.h
    #import <Foundation/Foundation.h>
    
    @interface People : NSObject
    
    @end
    
    1. People.m
    #import "People.h"
    
    @implementation People
    
    @end
    

    3.实例调用:

    #import "ViewController.h"
    #import <objc/runtime.h>
    #import "People.h"
    @interface ViewController ()
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        [self class_addIvar];
    }
    
    - (void)class_addIvar{
        Class P_Class = objc_allocateClassPair([NSObject class], "_People", 0);
        BOOL isOk = NO;
        isOk = class_addIvar(P_Class,"myVar", sizeof(id), log2(sizeof(id)), "@");
        isOk == YES ? nil : NSLog(@"failed on class_addIvar");
        objc_registerClassPair(P_Class);
        id myobj = [[P_Class alloc] init];
        [myobj setValue:@"test" forKey:@"myVar"];
        NSLog(@"myVar: %@", [myobj valueForKey:@"myVar"]);
        myobj = nil;//当_People类或者它的子类的实例还存在,则不能调用objc_disposeClassPair这个方法;因此这里要先销毁实例对象后才能销毁类;
        objc_disposeClassPair(P_Class);
        
    }
    打印数据:
    2018-05-27 10:19:51.251273+0700 runTimer[14245:1323729] myVar: test
    

    总结:
    关于这个方法,说真的让我产生了一些疑惑,至今也没有得到答案,也希望看到这篇文章对runtime有一定理解朋友可以给予一定的解释,

    • 疑问一:objc_allocateClassPair 在刚开始我创建获取元类时我得到总是nil,在网上查了很多资料但是我没有得到答案,后来是因为自己是性的在累名前加“_” 竟然成功的获取了,我没有明白原因。
    • 疑问二:关于元类说实话我之前也是简单的知道,个人理解是关于类描述的一个类,但是我始终不能明白在元类中添加成员变量,这样做会苹果官方有什么样的深意。

    3 object_setIvar object_getIvar

    3.1相关函数

    //相当于set方法
    void object_setIvar(id obj, Ivar ivar, id value) 
    //相当于get方法
    id object_getIvar(id obj, Ivar ivar) 
    

    3.2实例代码

    1.People.h

    #import <Foundation/Foundation.h>
    
    @interface People : NSObject
    @property (nonatomic,strong)NSString *phone;
    @end
    
    
    1. People.m
    #import "People.h"
    
    @implementation People
    
    @end
    

    3.实例代码调用:

    #import "ViewController.h"
    #import <objc/runtime.h>
    #import <objc/message.h>
    #import "People.h"
    @interface ViewController ()
    @property (nonatomic,strong)People *p;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        
        Ivar ivar = class_getInstanceVariable([People class], "_phone");
        People *p = [[People alloc] init];
        p.phone = @"1322432423";
        id name1 = object_getIvar(p, ivar);
        NSLog(@"name1:%@",name1);
        object_setIvar(p, ivar, @"1322432423");
        id name2 = object_getIvar(p, ivar);
        NSLog(@"name2:%@",name2);
    }
    打印数据:
    2018-05-27 11:05:04.551576+0700 runTimer[14991:1353337] name1:1322432423
    2018-05-27 11:05:04.551717+0700 runTimer[14991:1353337] name2:1322432423
    
    

    总结:
    看到这里的时候我想大家已经很明白了 这两个方法 基本上等同于set get方法。

    4.未做解析方法:

    ivar_getOffset
    class_setWeakIvarLayout
    object_setIvarWithStrongDefault
    class_getWeakIvarLayout
    class_getIvarLayout
    

    好了 就那么多了 还有一些方法没有讲,太懒了,就不一一解析了。
    下一章,关于runtime 关于method的解析

    相关文章

      网友评论

      本文标题:iOS runtime(二)runtime之Ivar 详尽

      本文链接:https://www.haomeiwen.com/subject/hatujftx.html