分析Runtime的属性Property
一、介绍
在OC中我们可以给任意的一个类以@property的格式声明属性,当然对于这个属性也会采用某一些属性关键字进行修饰,那么属性的真正的面目是啥样子的呢?其实,runtime源码中可以看到,property是一个结构,如下所示,只不过苹果为这个结构体另外定义了一个结构体指针。
//属性结构体指针
typedef struct objc_property *objc_property_t;
二、函数
正如我们所知,MJExtension是一个非常流行的json解析框架,其内部对对象的每一个属性进行解析的方式其实就是通过runtime来实现的。runtime源码中提供了属性的相关API函数。通过这些函数,我们可以轻松的得到每一个属性名和类型以及特性,相关函数如下:
//获取一个属性
objc_property_t _Nullable class_getProperty(Class _Nullable cls, const char * _Nonnull name); //添加一个属性
class_addProperty(Class _Nullable cls, const char * _Nonnull name, const objc_property_attribute_t * _Nullable attributes,unsigned int attributeCount); //替换一个属性
class_replaceProperty(Class _Nullable cls, const char * _Nonnull name, const objc_property_attribute_t * _Nullable attributes,unsigned int attributeCount) //获取属性数组
objc_property_t _Nonnull * _Nullable class_copyPropertyList(Class _Nullable cls, unsigned int * _Nullable outCount); //获取属性名称
const char * _Nonnull property_getName(objc_property_t _Nonnull property) ; //获取属性描述名称
const char * _Nullable property_getAttributes(objc_property_t _Nonnull property); //获取属性描述数组
objc_property_attribute_t * _Nullable property_copyAttributeList(objc_property_t _Nonnull property,unsigned int * _Nullable outCount); //通过属性描述的name获取属性描述的value
property_copyAttributeValue(objc_property_t _Nonnull property,const char * _Nonnull attributeName); //属性描述结构体
typedef struct {
const char * _Nonnull name; /**< The name of the attribute */
const char * _Nonnull value; /**< The value of the attribute (usually empty) */
} objc_property_attribute_t;
三、案例
了解了基本函数后,现在来上手,获取并打印看看property到底是个啥样,代码如下:
//定义一个对象,声明各种属性property
@interface SubObject : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) void (^Block)(void);
@property (nonatomic, weak) id<NSObject> delegate;
@property (nonatomic, assign) int age;
@property (nonatomic, assign) float height;
@property (nonatomic, assign) double weight;
@property (nonatomic, strong) NSNumber *num;
@property (nonatomic, strong) NSDate *date;
@property (nonatomic, strong) NSData *data;
@property (nonatomic, strong) NSArray *array;
@property (nonatomic, strong) NSDictionary *dic;
@property (nonatomic, strong) MyObject *myObject;
@end
//获取属性列表
unsigned int count;
objc_property_t *properties = class_copyPropertyList([subObject class], &count);
for (int i=; i<count; i++) { //获取属性
objc_property_t property = properties[i]; //属性名称
const char *propertyName = property_getName(property);
NSLog(@"------propertyName = %s-------",propertyName); //属性描述名称
const char * property_attr = property_getAttributes(property);
NSLog(@"------property_attr = %s-------",property_attr); //属性类型
const char *propertyType = property_copyAttributeValue(property, "T");
NSLog(@"------propertyType = %s-------",propertyType); //属性变量名称
const char *property_Value = property_copyAttributeValue(property, "V");
NSLog(@"------property_Value = %s-------",property_Value); //属性描述列表
unsigned int outCount;
objc_property_attribute_t *attributeList = property_copyAttributeList(property, &outCount);
for (int j=; j<outCount; j++) {
objc_property_attribute_t attribute = attributeList[j];
NSLog(@"property_attribute_t_name:%s-----property_attribute_t_value:%s",attribute.name,attribute.value);
}
NSLog(@"");
}
-- ::10.335830+ 运行时[:] ------propertyName = name-------
-- ::10.336009+ 运行时[:] ------property_attr = T@"NSString",C,N,V_name-------
-- ::10.336152+ 运行时[:] ------propertyType = @"NSString"-------
-- ::10.336261+ 运行时[:] ------property_Value = _name-------
-- ::10.336405+ 运行时[:] property_attribute_t_name:T-----property_attribute_t_value:@"NSString"
-- ::10.336532+ 运行时[:] property_attribute_t_name:C-----property_attribute_t_value:
-- ::10.336648+ 运行时[:] property_attribute_t_name:N-----property_attribute_t_value:
-- ::10.336770+ 运行时[:] property_attribute_t_name:V-----property_attribute_t_value:_name
-- ::10.336877+ 运行时[:]
-- ::10.336974+ 运行时[:] ------propertyName = Block-------
-- ::10.337256+ 运行时[:] ------property_attr = T@?,C,N,V_Block-------
-- ::10.337568+ 运行时[:] ------propertyType = @?-------
-- ::10.337972+ 运行时[:] ------property_Value = _Block-------
-- ::10.338296+ 运行时[:] property_attribute_t_name:T-----property_attribute_t_value:@?
-- ::10.338638+ 运行时[:] property_attribute_t_name:C-----property_attribute_t_value:
-- ::10.341894+ 运行时[:] property_attribute_t_name:N-----property_attribute_t_value:
-- ::10.342363+ 运行时[:] property_attribute_t_name:V-----property_attribute_t_value:_Block
-- ::10.342769+ 运行时[:]
-- ::10.343143+ 运行时[:] ------propertyName = delegate-------
-- ::10.343664+ 运行时[:] ------property_attr = T@"<NSObject>",W,N,V_delegate-------
-- ::10.343779+ 运行时[:] ------propertyType = @"<NSObject>"-------
-- ::10.344314+ 运行时[:] ------property_Value = _delegate-------
-- ::10.344746+ 运行时[:] property_attribute_t_name:T-----property_attribute_t_value:@"<NSObject>"
-- ::10.345172+ 运行时[:] property_attribute_t_name:W-----property_attribute_t_value:
-- ::10.345485+ 运行时[:] property_attribute_t_name:N-----property_attribute_t_value:
-- ::10.345773+ 运行时[:] property_attribute_t_name:V-----property_attribute_t_value:_delegate
-- ::10.346062+ 运行时[:]
-- ::10.346475+ 运行时[:] ------propertyName = age-------
-- ::10.346859+ 运行时[:] ------property_attr = Ti,N,V_age-------
-- ::10.347278+ 运行时[:] ------propertyType = i-------
-- ::10.347784+ 运行时[:] ------property_Value = _age-------
-- ::10.348131+ 运行时[:] property_attribute_t_name:T-----property_attribute_t_value:i
-- ::10.348551+ 运行时[:] property_attribute_t_name:N-----property_attribute_t_value:
-- ::10.348980+ 运行时[:] property_attribute_t_name:V-----property_attribute_t_value:_age
-- ::10.349373+ 运行时[:]
-- ::10.349737+ 运行时[:] ------propertyName = height-------
-- ::10.350087+ 运行时[:] ------property_attr = Tf,N,V_height-------
-- ::10.350393+ 运行时[:] ------propertyType = f-------
-- ::10.350763+ 运行时[:] ------property_Value = _height-------
-- ::10.351191+ 运行时[:] property_attribute_t_name:T-----property_attribute_t_value:f
-- ::10.351596+ 运行时[:] property_attribute_t_name:N-----property_attribute_t_value:
-- ::10.351971+ 运行时[:] property_attribute_t_name:V-----property_attribute_t_value:_height
-- ::10.352397+ 运行时[:]
-- ::10.352694+ 运行时[:] ------propertyName = weight-------
-- ::10.353102+ 运行时[:] ------property_attr = Td,N,V_weight-------
-- ::10.353529+ 运行时[:] ------propertyType = d-------
-- ::10.353791+ 运行时[:] ------property_Value = _weight-------
-- ::10.354096+ 运行时[:] property_attribute_t_name:T-----property_attribute_t_value:d
-- ::10.354411+ 运行时[:] property_attribute_t_name:N-----property_attribute_t_value:
-- ::10.354693+ 运行时[:] property_attribute_t_name:V-----property_attribute_t_value:_weight
-- ::10.355023+ 运行时[:]
-- ::10.355303+ 运行时[:] ------propertyName = num-------
-- ::10.355567+ 运行时[:] ------property_attr = T@"NSNumber",&,N,V_num-------
-- ::10.355887+ 运行时[:] ------propertyType = @"NSNumber"-------
-- ::10.356349+ 运行时[:] ------property_Value = _num-------
-- ::10.357784+ 运行时[:] property_attribute_t_name:T-----property_attribute_t_value:@"NSNumber"
-- ::10.358246+ 运行时[:] property_attribute_t_name:&-----property_attribute_t_value:
-- ::10.358968+ 运行时[:] property_attribute_t_name:N-----property_attribute_t_value:
-- ::10.359325+ 运行时[:] property_attribute_t_name:V-----property_attribute_t_value:_num
-- ::10.359998+ 运行时[:]
-- ::10.360152+ 运行时[:] ------propertyName = date-------
-- ::10.360572+ 运行时[:] ------property_attr = T@"NSDate",&,N,V_date-------
-- ::10.360834+ 运行时[:] ------propertyType = @"NSDate"-------
-- ::10.361263+ 运行时[:] ------property_Value = _date-------
-- ::10.361579+ 运行时[:] property_attribute_t_name:T-----property_attribute_t_value:@"NSDate"
-- ::10.361951+ 运行时[:] property_attribute_t_name:&-----property_attribute_t_value:
-- ::10.362362+ 运行时[:] property_attribute_t_name:N-----property_attribute_t_value:
-- ::10.362838+ 运行时[:] property_attribute_t_name:V-----property_attribute_t_value:_date
-- ::10.363256+ 运行时[:]
-- ::10.363500+ 运行时[:] ------propertyName = data-------
-- ::10.363788+ 运行时[:] ------property_attr = T@"NSData",&,N,V_data-------
-- ::10.364093+ 运行时[:] ------propertyType = @"NSData"-------
-- ::10.364430+ 运行时[:] ------property_Value = _data-------
-- ::10.364925+ 运行时[:] property_attribute_t_name:T-----property_attribute_t_value:@"NSData"
-- ::10.365110+ 运行时[:] property_attribute_t_name:&-----property_attribute_t_value:
-- ::10.365525+ 运行时[:] property_attribute_t_name:N-----property_attribute_t_value:
-- ::10.365928+ 运行时[:] property_attribute_t_name:V-----property_attribute_t_value:_data
-- ::10.366541+ 运行时[:]
-- ::10.366648+ 运行时[:] ------propertyName = array-------
-- ::10.366929+ 运行时[:] ------property_attr = T@"NSArray",&,N,V_array-------
-- ::10.367389+ 运行时[:] ------propertyType = @"NSArray"-------
-- ::10.367686+ 运行时[:] ------property_Value = _array-------
-- ::10.368112+ 运行时[:] property_attribute_t_name:T-----property_attribute_t_value:@"NSArray"
-- ::10.368357+ 运行时[:] property_attribute_t_name:&-----property_attribute_t_value:
-- ::10.368664+ 运行时[:] property_attribute_t_name:N-----property_attribute_t_value:
-- ::10.368905+ 运行时[:] property_attribute_t_name:V-----property_attribute_t_value:_array
-- ::10.369409+ 运行时[:]
-- ::10.369565+ 运行时[:] ------propertyName = dic-------
-- ::10.369810+ 运行时[:] ------property_attr = T@"NSDictionary",&,N,V_dic-------
-- ::10.370092+ 运行时[:] ------propertyType = @"NSDictionary"-------
-- ::10.370366+ 运行时[:] ------property_Value = _dic-------
-- ::10.370706+ 运行时[:] property_attribute_t_name:T-----property_attribute_t_value:@"NSDictionary"
-- ::10.371128+ 运行时[:] property_attribute_t_name:&-----property_attribute_t_value:
-- ::10.371537+ 运行时[:] property_attribute_t_name:N-----property_attribute_t_value:
-- ::10.371911+ 运行时[:] property_attribute_t_name:V-----property_attribute_t_value:_dic
-- ::10.372340+ 运行时[:]
-- ::10.372762+ 运行时[:] ------propertyName = myObject-------
-- ::10.373469+ 运行时[:] ------property_attr = T@"MyObject",&,N,V_myObject-------
-- ::10.373751+ 运行时[:] ------propertyType = @"MyObject"-------
-- ::10.374167+ 运行时[:] ------property_Value = _myObject-------
-- ::10.374515+ 运行时[:] property_attribute_t_name:T-----property_attribute_t_value:@"MyObject"
-- ::10.374742+ 运行时[:] property_attribute_t_name:&-----property_attribute_t_value:
-- ::10.375014+ 运行时[:] property_attribute_t_name:N-----property_attribute_t_value:
-- ::10.375595+ 运行时[:] property_attribute_t_name:V-----property_attribute_t_value:_myObject
-- ::10.375718+ 运行时[:]
四、分析
看到上述打印,发现一些特性,可以获取到属性名称、属性类型,属性原子性、属性引用情况等,这些基本都在属性描述property_attr中,并使用一些特别的字符表示,例如T、@,&,N,V等,每一个属性描述都是以字符“T”开头,以字符“V下划线变量名 V_xxx”结尾 (结尾不固定,对于其他属性)。
例如属性name的属性描述打印:
//T: Type(@encode) 属性类型
//@: 对象类型, NSString类型
//C: Copy 拷贝特性
//N: nonatomic 非原子性,默认为atomic,atomic为空
//V:variable 变量 _name , 使用@property修饰的属性系统默认@synthesize定义下划线变量,_name
property_attr = T@"NSString",C,N,V_name
例如属性age的属性描述打印:
//T: Type(@encode) 属性类型
//i: 基本数据类型, int类型//N: nonatomic 非原子性,默认为atomic,atomic为空
//V:variable 变量 _age , 使用@property修饰的属性系统默认@synthesize定义下划线变量,_age
property_attr = Ti,N,V_age-------
例如属性myObject的属性描述打印:
//T: Type(@encode) 属性类型
//@: 对象类型, 自定义类MyObject类型
//&: 引用特性, 强引用
//N: nonatomic 非原子性,默认为atomic,atomic为空
//V:variable 变量 _myObject-- , 使用@property修饰的属性系统默认@synthesize定义下划线变量,_myObject--
property_attr = T@"MyObject",&,N,V_myObject-------
就不一一列举了,基本属性特性大概如下,可能不完整:
//基本字符表示
T 是固定开头,表示类型,后跟类型 @、i、f、d、#等
& 代表强引用
C 代表copy
R 代表readOnly属性,readwrite时为空
W 代表weak,assign为空,默认为assign。
N 区分的nonatomic和atomic,默认为atomic,atomic为空,’N’代表是nonatomic
D @dynamic 动态特性,动态绑定,需要手动生成setter和getter方法
V_exprice 固定结尾,V代表变量,后面紧跟着的是成员变量名,代表这个property的成员变量名为_exprice。
属性类型的表示字符特性编码苹果官方给了一套参考:特性编码解析大全
//编码值 含意
//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…} 代表struct结构体
//(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),代表未知类型,例如block
四、扩展
类的属性声明
//类拥有一个属性
NS_ASSUME_NONNULL_BEGIN
@interface MyObject : NSObject
@property (nonatomic, copy) NSString *name;
@end
1、获取
-(void)printPropertyWithObj:(MyObject *)myObject{
unsigned int count;
objc_property_t *properties = class_copyPropertyList([myObject class], &count);
for (int i=; i<count; i++) { //获取属性
objc_property_t property = properties[i]; //属性名称
const char *propertyName = property_getName(property);
NSLog(@"------propertyName = %s-------",propertyName); //属性变量
char *property_Value = property_copyAttributeValue(property, "V");
NSLog(@"------property_Value = %s-------",property_Value); //属性类型
char *property_Type = property_copyAttributeValue(property, "T");
NSLog(@"------property_Type = %s-------",property_Type);
}
}
-- ::24.258232+ 运行时[:] ------propertyName = name-------
-- ::24.258412+ 运行时[:] ------property_Value = _name-------
-- ::24.258541+ 运行时[:] ------property_Type = @"NSString"-------
2、添加
//添加属性
//* @param cls The class to modify.
//* @param name The name of the property.
//* @param attributes An array of property attributes.
//* @param attributeCount The number of attributes in \e attributes.
//class_addProperty(Classcls, const char *name, const objc_property_attribute_t *attributes,unsigned int attributeCount)
const char * propertyName = "age";
objc_property_attribute_t type = { "T", "i" }; //int
objc_property_attribute_t ownership = { "N" }; //nonatomic
objc_property_attribute_t variable = { "V", "_age" }; //_age
objc_property_attribute_t attrs[] = { type, ownership, variable };
BOOL addSuccess = class_addProperty([myObject class], propertyName, attrs, );
if (addSuccess) {
[self printPropertyWithObj:myObject];
}
-- ::12.120742+ 运行时[:] 默认属性如下:
-- ::12.120941+ 运行时[:] ------propertyName = name-------
-- ::12.121073+ 运行时[:] ------property_Value = _name-------
-- ::12.121199+ 运行时[:] ------property_Type = @"NSString"-------
-- ::12.121295+ 运行时[:]
-- ::12.121405+ 运行时[:] 添加属性如下:
-- ::12.121617+ 运行时[:] ------propertyName = age-------
-- ::12.121731+ 运行时[:] ------property_Value = _age-------
-- ::12.121886+ 运行时[:] ------property_Type = i-------
-- ::12.122279+ 运行时[:] ------propertyName = name-------
-- ::12.122780+ 运行时[:] ------property_Value = _name-------
-- ::12.123222+ 运行时[:] ------property_Type = @"NSString"-------
3、替换
//替换属性【注意:无法改变属性名称,只是修改生成的下划线变量,_variable】
//* @param cls The class to modify.
//* @param name The name of the property.
//* @param attributes An array of property attributes.
//* @param attributeCount The number of attributes in \e attributes.
//class_replaceProperty(Class cls, const char *name, const objc_property_attribute_t * _Nullable attributes, unsigned int attributeCount)
const char * propertyName = "name";
objc_property_attribute_t type = { "T", "@\"NSString\"" };//NSString
objc_property_attribute_t ownership = { "C", "N" }; // copy、nonatomic
objc_property_attribute_t variable = { "V", "_newName" }; //_newName
objc_property_attribute_t attrs[] = { type, ownership, variable };
class_replaceProperty([myObject class], propertyName, attrs, );
[self printPropertyWithObj:myObject];
-- ::52.448875+ 运行时[:] 默认属性如下:
-- ::52.450451+ 运行时[:] ------propertyName = name-------
-- ::52.452714+ 运行时[:] ------property_Value = _name-------
-- ::52.453001+ 运行时[:] ------property_Type = @"NSString"-------
-- ::52.453125+ 运行时[:]
-- ::52.458433+ 运行时[:] 替换属性如下:
-- ::52.458658+ 运行时[:] ------propertyName = name-------
-- ::52.463156+ 运行时[:] ------property_Value = _newName-------
-- ::52.463973+ 运行时[:] ------property_Type = @"NSString"-------
分析Runtime的属性Property的更多相关文章
- iOS runtime探究(三): 从runtime開始理解OC的属性property
你要知道的runtime都在这里 转载请注明出处 http://blog.csdn.net/u014205968/article/details/67639303 本文主要解说runtime相关知识, ...
- Yii2基本概念之——属性(property)
学习任何一门学问,往往都是从起基本的概念学起.万丈高楼平地起,这些基本概念就是高楼的基石,必须做详尽的分析.我们知道,Yii2是一款脉络清晰的框架,理顺了基础的概念和基本功能,学习更高级和复杂的功能就 ...
- 区分元素特性attribute和对象属性property
× 目录 [1]定义 [2]共有 [3]例外[4]特殊[5]自定义[6]混淆[7]总结 前面的话 其实attribute和property两个单词,翻译出来都是属性,但是<javascript高 ...
- 属性(@property)、@synthesize
先前我们学的实例变量是这样的 { int _age; int _height; int age; } 后来学属性 @property int age; 看到@property 会自动编译生成某个成员变 ...
- Object的属性property详细解释(自动生成成员变量)
类Class中的属性property: 在ios第一版中,我们为输出口同时声明了属性和底层实例变量,那时,属性是oc语言的一个新的机制,并且要求你必须声明与之对应的实例变量,例如: @interfac ...
- OC 实例变量(instance var)与属性(@property)的关系 isa指针
实例变量(instance var)与属性(@property)的关系 Objective-C 2.0之后,声明一个@property name自动产生一个实例变量,名为_name,因此省去实例变量和 ...
- iOS中属性Property的常用关键字的使用说明
属性关键字的作用 现在我们iOS开发中,基本都是使用ARC(自动引用计数)技术,来编写我们的代码.因此在属性property中我们经常使用的关键字有strong,weak,assign,copy,no ...
- Effective C# 学习笔记(原则一:始终能的使用属性(property),而不是可直接访问的Data Member)
原则一:始终能的使用属性(property),而不是可直接访问的Data Member Always use properties instead of accessible data memb ...
- 对用户控件(ascx)属性(property)赋值
对用户控件(ascx)属性(property)赋值 Insus.NET写此博文,是对用户控件(ASCX)的属性赋值经验与技巧分享.是这样子的,在做新闻站点时,一般都会有分很多类别. 在站点首页会显示最 ...
随机推荐
- 国内的go get问题的解决 --gopm
一.golang之旅--gopm 1.什么是gopm 在nodejs中我们有npm,可以通过npm来下载安装一些依赖包.在go中也开发了类似的东西,那就是gopm.这玩意儿是七牛开发的.在这里说下,七 ...
- Custom Diagrams
Custom Diagrams https://github.com/dbeaver/dbeaver/wiki/Custom-Diagrams You can create custom ER dia ...
- 打通 DevOps 任督二脉 ,CODING 2.0 制品库全新上线
CODING 在近期的 KubeCon 2019 大会上发布了 CODING 2.0,同时发布了最新功能--制品库.CODING 不断完善 DevOps 工具链,旨在持续提升研发组织软件交付的速度与质 ...
- 【pycharm】Unable to save settings: Failed to save settings. Please restart PyCharm解决
1.Unable to save settings: Failed to save settings. Please restart PyCharm解决 将工程的.idea目录删掉,重启pycharm ...
- Java_foreach不能remove
foreach 阿里巴巴java开发手册 [强制]不要在foreach循环里进行元素的remove/add操作.remove元素请使用Iterator方式,如果并发操作,需要对Iterator对象加锁 ...
- maven与gradle的阿里云仓库配置
直接参考 https://help.aliyun.com/document_detail/102512.html 就好. 阿里云maven仓库官网 https://maven.aliyun.com/m ...
- qq cookie
qq cookie from selenium import webdriver from selenium.webdriver import ActionChains import time, re ...
- 关于在maven项目中配置文件资源导出问题
标准的Maven项目都会有一个resources目录来存放我们所有的资源配置文件,但是我们往往在项目中不仅仅会把所有的资源配置文件都放在resources中,同时我们也有可能放在项目中的其他位置,那么 ...
- Ruby入门1
由于部门的自动化是由一个前辈实现的,他使用的Ruby的语言来实现的,所以需要学习一下Ruby语言,争取在15天左右可以掌握Ruby语言!加油~~~ 1.常量&变量 # 1.常量 # 一般用大写 ...
- Java入门系列之集合LinkedList源码分析(九)
前言 上一节我们手写实现了单链表和双链表,本节我们来看看源码是如何实现的并且对比手动实现有哪些可优化的地方. LinkedList源码分析 通过上一节我们对双链表原理的讲解,同时我们对照如下图也可知道 ...