分析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)的属性赋值经验与技巧分享.是这样子的,在做新闻站点时,一般都会有分很多类别. 在站点首页会显示最 ...
随机推荐
- V4 Reduce Transportable Tablespace Downtime using Cross Platform Incremental Backup (Doc ID 2471245.1)
V4 Reduce Transportable Tablespace Downtime using Cross Platform Incremental Backup (Doc ID 2471245. ...
- [Go] 实现面向对象中的继承和覆盖方法
go中的继承是使用结构体嵌套实现的,可以继承父类的方法 覆盖和其他面向对象的语言是一样的,函数名,参数,返回类型一致,就可以覆盖父类的方法 package main import "log& ...
- robotframework框架 - 利用RequestsLibrary关键字轻松实现接口自动化!
robotframework(后续简称为robot)是一款自动化测试框架,可能做各种类型的自动化测试. 本文介绍通过robotframework来做接口测试. 第一步:安装第三方库,提供接口测试的关键 ...
- 解决tail命令提示“tail: inotify 资源耗尽,无法使用 inotify 机制,回归为 polling 机制”
报错的原因是 inotify 跟踪的文件数量超出了系统设置的上限值,要是这个问题不经常出现可以使用临时解决方法,或者写入配置文件来永久解决. 临时解决方法: # 查看 inotify 的相关配置 $ ...
- 通过jgit一次性升级fastjson版本
背景:笔者所在公司经历了三次fastjson的升级,由于集群,工程数量众多,每次升级都很麻烦.因此开发了一个java的升级工具. 功能介绍: 功能介绍:一个jar文件,通过java -jar命令,输入 ...
- PHP实现微信提现功能
提现必须得用双向证书.所以大家一定要在微信的商户平台找到相应的地方去设置.因为做这个提现已经有一段时间了.所以设置微信商户平台的那几个地方没有图的情况.也说不清楚.下次再做提现的时候.给大家分享如何设 ...
- 聊聊 Java8 以后各个版本的新特性
作者:ZY5A59 juejin.im/post/5d5950806fb9a06b0a277412 某天在网上闲逛,突然看到有篇介绍 Java 11 新特性的文章,顿时心里一惊,毕竟我对于 Java ...
- BeautifulSoup的重要操作
BeautifulSoup相关概念总结:https://www.cnblogs.com/pythonywy/p/11134481.html css基础以及选择器基础:https://www.cnblo ...
- SpringBoot+MyBatisPlus整合时提示:Invalid bound statement(not found):**.dao.UserDao.queryById
场景 在使用SpringBoot+MyBatisPlus搭建后台启动项目时,使用EasyCode自动生成代码. 在访问后台接口时提示: Invilid bound statement (not fou ...
- PHP fnmatch 文件系统函数
定义和用法 fnmatch - 用模式匹配文件名 目前该函数无法在 Windows 或其它非 POSIX 兼容的系统上使用. 版本支持 PHP4 PHP5 PHP7 4.3.0(含)+支持 支持 支持 ...