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

你要知道的runtime都在这里

转载请注明出处 http://blog.csdn.net/u014205968/article/details/67639303

本文主要解说runtime相关知识,从原理到实践。因为包括内容过多分为下面五篇文章具体解说,可自行选择须要了解的方向:

本文是系列文章的第三篇文章从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;
}

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

备注

因为作者水平有限,难免出现纰漏,如有问题还请指教。

【推广】 免费学中医,健康全家人
原文地址:https://www.cnblogs.com/zhchoutai/p/8931419.html