iOS runtime(一)runtime之Property 详尽

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 详解晚更~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,204评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,091评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,548评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,657评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,689评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,554评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,302评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,216评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,661评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,851评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,977评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,697评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,306评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,898评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,019评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,138评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,927评论 2 355

推荐阅读更多精彩内容