一、介绍

在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的更多相关文章

  1. iOS runtime探究(三): 从runtime開始理解OC的属性property

    你要知道的runtime都在这里 转载请注明出处 http://blog.csdn.net/u014205968/article/details/67639303 本文主要解说runtime相关知识, ...

  2. Yii2基本概念之——属性(property)

    学习任何一门学问,往往都是从起基本的概念学起.万丈高楼平地起,这些基本概念就是高楼的基石,必须做详尽的分析.我们知道,Yii2是一款脉络清晰的框架,理顺了基础的概念和基本功能,学习更高级和复杂的功能就 ...

  3. 区分元素特性attribute和对象属性property

    × 目录 [1]定义 [2]共有 [3]例外[4]特殊[5]自定义[6]混淆[7]总结 前面的话 其实attribute和property两个单词,翻译出来都是属性,但是<javascript高 ...

  4. 属性(@property)、@synthesize

    先前我们学的实例变量是这样的 { int _age; int _height; int age; } 后来学属性 @property int age; 看到@property 会自动编译生成某个成员变 ...

  5. Object的属性property详细解释(自动生成成员变量)

    类Class中的属性property: 在ios第一版中,我们为输出口同时声明了属性和底层实例变量,那时,属性是oc语言的一个新的机制,并且要求你必须声明与之对应的实例变量,例如: @interfac ...

  6. OC 实例变量(instance var)与属性(@property)的关系 isa指针

    实例变量(instance var)与属性(@property)的关系 Objective-C 2.0之后,声明一个@property name自动产生一个实例变量,名为_name,因此省去实例变量和 ...

  7. iOS中属性Property的常用关键字的使用说明

    属性关键字的作用 现在我们iOS开发中,基本都是使用ARC(自动引用计数)技术,来编写我们的代码.因此在属性property中我们经常使用的关键字有strong,weak,assign,copy,no ...

  8. Effective C# 学习笔记(原则一:始终能的使用属性(property),而不是可直接访问的Data Member)

    原则一:始终能的使用属性(property),而不是可直接访问的Data Member    Always use properties instead of accessible data memb ...

  9. 对用户控件(ascx)属性(property)赋值

    对用户控件(ascx)属性(property)赋值 Insus.NET写此博文,是对用户控件(ASCX)的属性赋值经验与技巧分享.是这样子的,在做新闻站点时,一般都会有分很多类别. 在站点首页会显示最 ...

随机推荐

  1. Android框架式编程之ViewModel

    一.ViewModel介绍 ViewModel类是被设计用来以可感知生命周期的方式存储和管理 UI 相关数据.ViewModel中数据会一直存活即使 Activity Configuration发生变 ...

  2. Git问题汇总

    1.fatal: refusing to merge unrelated histories $git pull origin master --allow-unrelated-histories 2 ...

  3. Goland快捷键(Macbook)

    Goland快捷键(Macbook) 基础编辑快键键 向上或向下移动当前行 ⇧⌘↑ ⇧⌘↓ 复制并粘贴当前选中的语句 ⌘D 删除当前行 ⌘⌫ 行注释 ⌘/ 块注释 ⌥⌘/ 在当前打开的文件中寻找 ⌘F ...

  4. sqlserver的表变量在没有预估偏差的情况下,与物理表可join产生的性能问题

    众所周知,在sqlserver中,表变量最大的特性之一就是没有统计信息,无法较为准备预估其数据分布情况,因此不适合参与较为复杂的SQL运算.当SQL相对简单的时候,使用表变量,在某些场景下,即便是对表 ...

  5. Django实现标签联动以及xadmin中实现标签联动

    如图,即实现点击一个城市,出现对应的学校名称.开始一直以为是建立数据表的时候实现的,原来是通过ajax实现的. 思路:当get请求显示原始状态(即下拉框呈现全部内容).当点击一个城市后,通过ajax的 ...

  6. Opencv中图像height width X 轴 Y轴 rows cols之间的对应关系

    这里做一个备忘录:

  7. 【tf.keras】TensorFlow 1.x 到 2.0 的 API 变化

    TensorFlow 2.0 版本将 keras 作为高级 API,对于 keras boy/girl 来说,这就很友好了.tf.keras 从 1.x 版本迁移到 2.0 版本,需要修改几个地方. ...

  8. VUE脚手架使用

    什么是vue脚手架?   他是一个快速构建vue项目的工具,通过他,我们可以将vue所需要的文件安装完成. vue-cli这个构建工具大大降低了webpack的使用难度,支持热更新,有webpack- ...

  9. ModuleNotFoundError: No module named 'xxx'; 'xxx' is not a package

    错误: ModuleNotFoundError: No module named 'xxx'; 'xxx' is not a package 通过pycharm对脚本进行debug时,出现了如下错: ...

  10. Java 创建线程的3种方法及各自优势

    1. 继承 Thread 类,然后调用 start 方法. class MyThread extends Thread { //重写run方法,线程运行后,跑的就是run方法 public void ...