分析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)的属性赋值经验与技巧分享.是这样子的,在做新闻站点时,一般都会有分很多类别. 在站点首页会显示最 ...
随机推荐
- 推荐一个好用的行内可编辑的table组件 vxe-table
项目中有一个需要用户点击table单元格可编辑的需求,由于博主用的是elementUI,element组件内实现可编辑,用过的小伙伴都知道,非常麻烦,后来博主在浏览组件的时候发现了 一款非常好用的ta ...
- ORA-27090: Unable to reserve kernel resources for asynchronous disk I/O
2019-08-19T09:27:33.225584+08:00Slave encountered ORA-27090 exception during crash recoveryRecovery ...
- linux 启动jar包 指定yml配置文件和输入日志文件
命令为: nohup java -jar project.jar --spring.config.location=/home/project-conf/application.yml > ...
- 第04组 Beta冲刺(1/4)
队名:斗地组 组长博客:地址 作业博客:Beta冲刺(1/4) 各组员情况 林涛(组长) 过去两天完成了哪些任务: 1.分配展示任务 2.收集各个组员的进度 3.写博客 展示GitHub当日代码/文档 ...
- 【docker构建】基于docker搭建redis数据库缓存服务
搭建redis服务 首先拉取镜像==>运行镜像为容器 # 先搜索下redis镜像 [root@VM_0_10_centos wordpress]# docker search redis # 拉 ...
- phpredis 报错 “Function Redis::setTimeout() is deprecated” 解决方法
项目在本地开发过程中抛出异常: Function Redis::setTimeout() is deprecated 找到出错代码: <?php use Illuminate\Support\F ...
- vue定义data的三种方式与区别
在vue中,定义data可以有三种写法. 1.第一种写法,对象. var app = new Vue({ el: '#yanggb', data: { yanggb: 'yanggb' } }) 2. ...
- 架构组件:基于Shard-Jdbc分库分表,数据库扩容方案
本文源码:GitHub·点这里 || GitEE·点这里 一.数据库扩容 1.业务场景 互联网项目中有很多"数据量大,业务复杂度高,需要分库分表"的业务场景. 这样分层的架构 (1 ...
- 常用类-ExcelHelper
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.D ...
- JPA入门简介与搭建HelloWorld(附代码下载)
场景 在学习JPA之前先来了解下JDBC与各大数据库的关系. 很久之前出现了很多数据库比如Mysql.Oracle.SqlServer.DB2等.这就导致了应用程序要连哪个数据库就要使用哪个数据库的A ...