iOS runtime探究(三): 从runtime开始理解OC的属性property你要知道的runtime都在这里

你要知道的runtime都在这里

转载请注明出处 https://cloud.tencent.com/developer/user/1605429

本文主要讲解runtime相关知识,从原理到实践,由于包含内容过多分为以下五篇文章详细讲解,可自行选择需要了解的方向:

  • 从runtime开始: 理解面向对象的类到面向过程的结构体
  • 从runtime开始: 深入理解OC消息转发机制
  • 从runtime开始: 理解OC的属性property
  • 从runtime开始: 实践Category添加属性与黑魔法method swizzling
  • 从runtime开始: 深入weak实现机理

本文是系列文章的第三篇文章从runtime开始: 理解OC的属性property,主要从runtime出发讲解属性property相关的底层实现和相关方法,由于之前的博客已经详细讲解了property的底层实现,所以本文不再赘述,如有需要可以查看相关文章:iOS @property探究(一): 基础详解该文主要讲解property的基础以及修饰符详解,iOS @property探究(二): 深入理解该文主要深入代码理解property的底层实现,由于与本文的内容由很大的重复,因此本文不再赘述上述相关内容。

本文将会讲解一些runtime操作属性的相关方法。

首先回顾一下相关代码以及与property底层实现相关的两个结构体:

//OC自定义类的定义
@interface Person : NSObject

@property (nonatomic, copy) NSString* cjmName;
@property (nonatomic, assign) NSUInteger cjmAge;

@end

@implementation Person

@synthesize cjmName = _cjmName;
@synthesize cjmAge = _cjmAge;

@end


//clang转写为.cpp的相关代码
struct _prop_t {
        const char *name;
        const char *attributes;
};

static struct /*_prop_list_t*/ {
        unsigned int entsize;  // sizeof(struct _prop_t)
        unsigned int count_of_properties;
        struct _prop_t prop_list[2];
} _OBJC_$_PROP_LIST_Person __attribute__ ((used, section ("__DATA,__objc_const"))) = {
        sizeof(_prop_t),
        2,
        {{"cjmName","T@\"NSString\",C,N,V_cjmName"},
        {"cjmAge","TQ,N,V_cjmAge"}}
};

通过上述代码其实我们可以看出,一个@property属性在底层就是一个结构体描述,那么我们如何获取这个结构体呢?可以通过如下代码获取:

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Person* p = [[Person alloc] init];
        p.cjmName = @"Jiaming Chen";
        
        unsigned int propertyCount = 0;
        objc_property_t *propertyList = class_copyPropertyList([p class], &propertyCount);
        for (int i = 0; i < propertyCount; i++) {
            const char* name = property_getName(propertyList[i]);
            const char* attributes = property_getAttributes(propertyList[i]);
            NSLog(@"%s %s", name, attributes);
        }
    }
    return 0;
}

首先看一下objc_property_t是什么,在objc/runtime.h中可以找到相关定义:

typedef struct objc_property *objc_property_t;

它是一个指向结构体struct objc_property的指针,这里的结构体struct objc_property其实就是前文中.cpp文件中的struct _prop_t结构体,通过class_copyPropertyList方法就可以获取到相关类的所有属性,具体函数声明如下:

/** 
 * Describes the properties declared by a class.
 * 
 * @param cls The class you want to inspect.
 * @param outCount On return, contains the length of the returned array. 
 *  If \e outCount is \c NULL, the length is not returned.        
 * 
 * @return An array of pointers of type \c objc_property_t describing the properties 
 *  declared by the class. Any properties declared by superclasses are not included. 
 *  The array contains \c *outCount pointers followed by a \c NULL terminator. You must free the array with \c free().
 * 
 *  If \e cls declares no properties, or \e cls is \c Nil, returns \c NULL and \c *outCount is \c 0.
 */
OBJC_EXPORT objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount)
    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);

通过注释可以看出,第一个参数是相关类的类对象(如有疑问可以查阅本系列文章的前两篇文章),第二个参数是一个指向unsigned int的指针,用于指明property的数量,通过该方法就能够获取到所有的属性,接下来可以通过property_getNameproperty_getAttributes方法获取该属性描述的nameattributes值,输出的结果如下:

2017-03-27 09:59:20.914487 OCTest[2467:460742] cjmName T@"NSString",C,N,V_cjmName
2017-03-27 09:59:20.915321 OCTest[2467:460742] cjmAge TQ,N,V_cjmAge

name很好理解,后面的attributes通过对比不难发现其规律,感兴趣的读者也可以多设置几个不同类型、不同修饰符的property看一下输出。

除此之外哈有一下几个方法用于根据属性名获取一个属性描述结构体、添加属性、替换属性等方法。

/** 
 * Returns a property with a given name of a given class.
 * 
 * @param cls The class you want to inspect.
 * @param name The name of the property you want to inspect.
 * 
 * @return A pointer of type \c objc_property_t describing the property, or
 *  \c NULL if the class does not declare a property with that name, 
 *  or \c NULL if \e cls is \c Nil.
 */
OBJC_EXPORT objc_property_t class_getProperty(Class cls, const char *name)
    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
    
/** 
 * Adds a property to a class.
 * 
 * @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.
 * 
 * @return \c YES if the property was added successfully, otherwise \c NO
 *  (for example, the class already has that property).
 */
OBJC_EXPORT BOOL class_addProperty(Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount)
    OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0);

/** 
 * Replace a property of a class. 
 * 
 * @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. 
 */
OBJC_EXPORT void class_replaceProperty(Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount)
    OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0);

举个简单的栗子:

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Person* p = [[Person alloc] init];
        p.cjmAge = 20;
        p.cjmName = @"Jiaming Chen";
        
        unsigned int propertyCount = 0;
        objc_property_t *propertyList = class_copyPropertyList([p class], &propertyCount);
        for (int i = 0; i < propertyCount; i++) {
            const char* name = property_getName(propertyList[i]);
            const char* attributes = property_getAttributes(propertyList[i]);
            NSLog(@"%s %s", name, attributes);
        }
        objc_property_attribute_t attributes = {
            "T@\"NSString\",C,N,V_studentIdentifier",
            "",
        };
        class_addProperty([p class], "studentIdentifier", &attributes, 1);
        objc_property_t property = class_getProperty([p class], "studentIdentifier");
        NSLog(@"%s %s", property_getName(property), property_getAttributes(property));
    }
    return 0;
}

通过上述方法就能添加一个属性,由于本人水平有限实际开发中没有用过上述方法,具体实际例子也举不出来所以不再过多赘述。

备注

由于作者水平有限,难免出现纰漏,如有问题还请不吝赐教。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏PingCAP的专栏

SuRF: 一个优化的 Fast Succinct Tries

在前一篇文章中,我简单介绍了 Succinct Data Structure,这里我们继续介绍 SuRF。

35150
来自专栏DannyHoo的专栏

构造方法、类方法、类的复合

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010105969/article/details/...

13710
来自专栏猿人谷

面试必备:HashMap、Hashtable、ConcurrentHashMap的原理与区别

HashMap和Hashtable都是用hash算法来决定其元素的存储,因此HashMap和Hashtable的hash表包含如下属性:

20010
来自专栏GIS讲堂

用GeoTools实现shp+sld导出图片

24030
来自专栏程序员Gank

iOS-代码规范

利用上周的业余时间把这篇规范整理了出来,我会将这篇规范作为我们iOS团队的代码规范,并且还会根据读者的反馈,项目的实践和研究的深入做不定时更新,还希望各位朋友看...

46320
来自专栏北京马哥教育

AWK处理日志入门

前言 这两天自己挽起袖子处理日志,终于把AWK给入门了。其实AWK的基本使用,学起来也就半天的时间,之前总是靠同事代劳,惰性呀。 此文仅为菜鸟入门,运维们请勿...

38740
来自专栏GIS讲堂

Geotools中蜂巢的实现

18320
来自专栏SDNLAB

Open vSwitch系列之数据结构解析深入分析ofpbuf

上一篇我们分析了hmap,hamp可以说是Open vSwitch中基石结构,很多Open vSwitch中数据结构都依赖hmap。本篇我们来分析一下ofpbu...

38980
来自专栏蓝天

sed 学习笔记(转)

声明:这些代码只是为了学习和理解sed命令而为之,并不代表问题的唯一解或最佳解,希望各位拍砖

8520
来自专栏君赏技术博客

关于对类别 延展 协议 一些属性声明词的用法

如果想给已经封装好的类添加方法 比如给UIButton添加一个异步下载图片的方法可以使用分类。比如我们要增加的方法需要实例变量很多 里面要用到很多的实例变量来执...

9030

扫码关注云+社区

领取腾讯云代金券