美文网首页iOS程序猿IOSNSObject的前世今生
iOS runtime(一)runtime之Property 详

iOS runtime(一)runtime之Property 详

作者: 奔跑吧小蚂蚁 | 来源:发表于2018-05-24 13:20 被阅读131次

    runtime官方文章学习大纲

    1. 读取类的Property属性

    1.1相关函数

    typedef struct objc_property *objc_property_t;
    
      typedef struct {
          const char *name;           
          const char *value;          
      } objc_property_attribute_t;
    
    
    // 获取指定的属性
    objc_property_t class_getProperty ( Class cls, const char *name );
    // 获取属性列表
    objc_property_t * class_copyPropertyList ( Class cls, unsigned int *outCount );
    //获取属性名称
    const char * property_getName(objc_property_t _Nonnull property) 
    //获取属性特性
    const char *property_getAttributes(objc_property_t _Nonnull property) 
    //获取属性特性列表
    objc_property_attribute_t *property_copyAttributeList(objc_property_t property,unsigned int * outCount)
    //获取根据特定键获取想得到的属性特性
    char *property_copyAttributeValue(objc_property_t  property, const char * attributeName)
    

    1.2.案例代码:

    #import "ViewController.h"
    #import <objc/runtime.h>
    
    @interface ViewController ()
    
    @property (nonatomic,strong)NSString *name;
    @property (atomic,strong)NSString *age;
    @property (nonatomic,assign)BOOL isMan;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        [self class_copyPropertyList];
        
    }
    
    - (void)class_copyPropertyList{
        //得到当前class的所有属性
        unsigned int count;
        objc_property_t *properties = class_copyPropertyList([self class], &count);
        for (int i = 0; i<count; i++) {
            objc_property_t property = properties[i];
            //属性名
            //const char * property_name = property_getName(property);
            //属性描述
            //const char * property_attr = property_getAttributes(property);
            //获取属性类型
            //const char *propertyType = property_copyAttributeValue(property, "T");
            //属性名
            //const char *property_Value = property_copyAttributeValue(property, "V");
            //NSLog(@"property_name:%s \n property_attr:%s \n propertyType:%s \n property_Value:%s",property_name, property_attr, propertyType,property_Value);
            //属性名
            NSString *property_name = @(property_getName(property));
            //属性描述
            NSString *property_attr = @(property_getAttributes(property));
            //获取属性类型
            NSString *propertyType = @(property_copyAttributeValue(property, "T"));
            //属性名
            NSString *property_Value = @(property_copyAttributeValue(property, "V"));
            NSLog(@"\n property_name:%@ \n property_attr:%@ \n propertyType:%@ \n property_Value:%@",property_name,property_attr,propertyType,property_Value);
            unsigned int attributeCount;
            objc_property_attribute_t *attributeList = property_copyAttributeList(property, &attributeCount);
            for (unsigned int j = 0; j < attributeCount; j++) {
                objc_property_attribute_t attribute = attributeList[j];
                //const char *name = attribute.name;
                //const char *value = attribute.value;
                //NSLog(@"attribute name: %s, value: %s", name, value);
                NSString *name = @(attribute.name);
                NSString *value = @(attribute.value);
                NSLog(@"attribute name: %@, value: %@", name, value);
            }
            free(attributeList);
        }
        free(properties);
    }
    
    

    1.3.打印数据:

    2018-05-24 14:48:35.663763+0700 runtime [28461:2078183] 
     property_name:name 
     property_attr:T@"NSString",&,N,V_name 
     propertyType:@"NSString" 
     property_Value:_name
    2018-05-24 14:48:35.663940+0700 runtime [28461:2078183] attribute name: T, value: @"NSString"
    2018-05-24 14:48:35.664034+0700 runtime [28461:2078183] attribute name: &, value:
    2018-05-24 14:48:35.664124+0700 runtime [28461:2078183] attribute name: N, value:
    2018-05-24 14:48:35.664259+0700 runtime [28461:2078183] attribute name: V, value: _name
    2018-05-24 14:48:35.664399+0700 runtime [28461:2078183] 
     property_name:age 
     property_attr:T@"NSString",&,V_age 
     propertyType:@"NSString" 
     property_Value:_age
    2018-05-24 14:48:35.664516+0700 runtime [28461:2078183] attribute name: T, value: @"NSString"
    2018-05-24 14:48:35.664600+0700 runtime [28461:2078183] attribute name: &, value:
    2018-05-24 14:48:35.664677+0700 runtime [28461:2078183] attribute name: V, value: _age
    2018-05-24 14:48:35.664756+0700 runtime [28461:2078183] 
     property_name:isMan 
     property_attr:TB,N,V_isMan 
     propertyType:B 
     property_Value:_isMan
    2018-05-24 14:48:35.664850+0700 runtime [28461:2078183] attribute name: T, value: B
    2018-05-24 14:48:35.664934+0700 runtime [28461:2078183] attribute name: N, value:
    2018-05-24 14:48:35.665079+0700 runtime [28461:2078183] attribute name: V, value: _isMan
    

    1.4.分析:

    • property_getName:通过property_getName获取属性对象名称
    • property_getAttributes:通过property_getAttributes获取 属性的特性字符串 以 T@encode(type) 开头, 以 V实例变量名称 结尾,中间以特性编码填充.
    • property_copyAttributeList:为属性对象列表 等同于property_getAttributes 区别在于一个返回数组一个返回字符串。
    • objc_property_attribute_t:为property_copyAttributeList包含的数组对象
    • property_copyAttributeValue:获取对应的属性特性描述,可以理解为在property_copyAttributeList中的值都可以单独获取到。

    1.5.特性编码解析

    1.property_attribute为T@”NSString”,&,N,V_exprice时:
    T 是固定的,放在第一个
    @”NSString” 代表这个property是一个字符串对象
    & 代表强引用,其中与之并列的是:’C’代表Copy,’&’代表强引用,’W’表示weak,assign为空,默认为assign。
    N 区分的nonatomic和atomic,默认为atomic,atomic为空,’N’代表是nonatomic
    V_exprice V代表变量,后面紧跟着的是成员变量名,代表这个property的成员变量名为_exprice。
    
    2.property_attribute为T@”NSNumber”,R,N,V_yearsOld时:
    T 是固定的,放在第一个
    @”NSNumber” 代表这个property是一个NSNumber对象
    R 代表readOnly属性,readwrite时为空
    N 区分的nonatomic和atomic,默认为atomic,atomic为空,’N’代表是nonatomic
    V_yearsOld V代表变量,后面紧跟着的是成员变量名,代表这个property的成员变量名为_yearsOld。
    
    3.对应的编码值
    //下面对应的编码值可以在官方文档里面找到
    //编码值   含意
    //c     代表char类型
    //i     代表int类型
    //s     代表short类型
    //l     代表long类型,在64位处理器上也是按照32位处理
    //q     代表long long类型
    //C     代表unsigned char类型
    //I     代表unsigned int类型
    //S     代表unsigned short类型
    //L     代表unsigned long类型
    //Q     代表unsigned long long类型
    //f     代表float类型
    //d     代表double类型
    //B     代表C++中的bool或者C99中的_Bool
    //v     代表void类型
    //*     代表char *类型
    //@     代表对象类型
    //#     代表类对象 (Class)
    //:     代表方法selector (SEL)
    //[array type]  代表array
    //{name=type…}  代表结构体
    //(name=type…)  代表union
    //bnum  A bit field of num bits
    //^type     A pointer to type
    //?     An unknown type (among other things, this code is used for function pointers)
    
    4.其他
    G(name) getter=(name)
    S(name) setter=(name)
    D @dynamic
    P 用于垃圾回收机制
    
    

    推荐解析文章
    特性编码解析大全
    案例图

    案例图.png

    1.6查漏补缺

    获取单个属性的信息

    #import "ViewController.h"
    #import <objc/runtime.h>
    
    @interface ViewController ()
    @property (nonatomic,strong)NSString *name;
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        [self class_getProperty:[self class] name:"name"];
    }
    
    - (void)class_getProperty:(Class)class name:(const char *)name {
        objc_property_t property = class_getProperty(class,name);
        NSString *property_name = @(property_getName(property));
        NSString *property_attr = @(property_getAttributes(property));
        NSString *property_Value = @(property_copyAttributeValue(property, "V"));
        NSString *property_Type = @(property_copyAttributeValue(property, "T"));
        NSLog(@"\n property_name:%@ \n property_attr:%@,\n property_Type:%@ \n property_Value:%@",property_name,property_attr,property_Type,property_Value);
    }
    打印数据:
    2018-05-24 16:51:58.266463+0700 runtime [29718:2161350] 
     property_name:name 
     property_attr:T@"NSString",&,N,V_name,
     property_Type:@"NSString" 
     property_Value:_name
    
    

    看代码就明白了,不解释了,很多知识由面到点,会更精彩一些。

    2.替换类的Property属性

    相关函数

    // 替换类的属性
    void class_replaceProperty ( Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount );
    
    

    实例代码:

    #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_replaceProperty:[self class] class_name:"name" replace_name:"nick_name"];
        //对name进行特性获取
        [self class_getProperty:[self class] name:"name"];
    }
    
    - (void)class_replaceProperty:(Class)class class_name:(const char *)class_name replace_name:(const char *)replace_name{
        objc_property_attribute_t type = { "T", "@\"NSString\"" };
        objc_property_attribute_t ownership = { "C", "" }; // C = copy
        objc_property_attribute_t backingivar  = { "V", replace_name };
        objc_property_attribute_t attrs[] = { type, ownership, backingivar };
        class_replaceProperty(class, class_name, attrs, 3);
    }
    - (void)class_getProperty:(Class)class name:(const char *)name {
        objc_property_t property = class_getProperty(class,name);
        NSString *property_name = @(property_getName(property));
        NSString *property_attr = @(property_getAttributes(property));
        NSString *property_Value = @(property_copyAttributeValue(property, "V"));
        NSString *property_Type = @(property_copyAttributeValue(property, "T"));
        NSLog(@"\n property_name:%@ \n property_attr:%@,\n property_Type:%@ \n property_Value:%@",property_name,property_attr,property_Type,property_Value);
    }
    

    分析:
    从打印数据的数据我们对比可以发,所谓替换属性并不是说直接讲声明的名称改掉,而是将属性特性值改为我们所需要的。

    3.为类添加Property

    相关函数

     BOOL class_addProperty(Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount)
    
    

    实例代码

    #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.
        //新增nick_name
        [self class_addProperty:[self class] add_name:"nick_name"];
        //对nick_name进行特性获取
        [self class_getProperty:[self class] name:"nick_name"];
    }
    
    
    
    - (void)class_addProperty:(Class)class add_name:(const char *)add_name {
        objc_property_attribute_t type = { "T", "@\"NSString\"" };
        objc_property_attribute_t ownership = { "&", "N" }; // C = copy
        objc_property_attribute_t backingivar  = { "V", "" };
        objc_property_attribute_t attrs[] = { type, ownership, backingivar };
        if (class_addProperty(class, add_name, attrs, 3)) {
            NSLog(@"添加属性--%sadd Property success",__func__);
        }else{
            NSLog(@"添加属性--%sadd Property fail",__func__);
        }
    }
    - (void)class_getProperty:(Class)class name:(const char *)name {
        objc_property_t property = class_getProperty(class,name);
        NSString *property_name = @(property_getName(property));
        NSString *property_attr = @(property_getAttributes(property));
        NSString *property_Value = @(property_copyAttributeValue(property, "V"));
        NSString *property_Type = @(property_copyAttributeValue(property, "T"));
        NSLog(@"\n property_name:%@ \n property_attr:%@,\n property_Type:%@ \n property_Value:%@",property_name,property_attr,property_Type,property_Value);
       
    }
    
    

    打印数据:

    2018-05-26 09:29:05.939306+0700 runTimer[5930:999110] 添加属性---[ViewController class_addProperty:add_name:]add Property success
    2018-05-26 09:29:05.939474+0700 runTimer[5930:999110] 
     property_name:nick_name 
     property_attr:T@"NSString",&N,V,
     property_Type:@"NSString" 
     property_Value:
    

    分析:
    对比替换属性进行分析,会更加透彻。

    runtime之Property 讲解就完毕了。不足指出还请指正。

    下一章:Ivar 详解晚更~

    相关文章

      网友评论

      • f7139db11dcd:可以给份注释的demo吗
        奔跑吧小蚂蚁:@HZW_sister 有问题大家可以一起讨论
        奔跑吧小蚂蚁:@HZW_sister 不好意思藕,我都是随手做随手试,没有完备的demo,可以加个关注,我最近这段时间会把runtime知识点分好类写全,每天都会有更新。

      本文标题:iOS runtime(一)runtime之Property 详

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