你要知道的runtime都在這里
轉(zhuǎn)載請(qǐng)注明出處 http://www.lxweimin.com/p/0623addb6b74
本文主要講解runtime
相關(guān)知識(shí),從原理到實(shí)踐,由于包含內(nèi)容過(guò)多分為以下五篇文章詳細(xì)講解,可自行選擇需要了解的方向:
- 從runtime開(kāi)始: 理解面向?qū)ο蟮念?lèi)到面向過(guò)程的結(jié)構(gòu)體
- 從runtime開(kāi)始: 深入理解OC消息轉(zhuǎn)發(fā)機(jī)制
- 從runtime開(kāi)始: 理解OC的屬性property
- 從runtime開(kāi)始: 實(shí)踐Category添加屬性與黑魔法method swizzling
- 從runtime開(kāi)始: 深入weak實(shí)現(xiàn)機(jī)理
本文是系列文章的第三篇文章從runtime開(kāi)始: 理解OC的屬性property,主要從runtime
出發(fā)講解屬性property
相關(guān)的底層實(shí)現(xiàn)和相關(guān)方法,由于之前的博客已經(jīng)詳細(xì)講解了property
的底層實(shí)現(xiàn),所以本文不再贅述,如有需要可以查看相關(guān)文章:iOS @property探究(一): 基礎(chǔ)詳解該文主要講解property
的基礎(chǔ)以及修飾符詳解,iOS @property探究(二): 深入理解該文主要深入代碼理解property
的底層實(shí)現(xiàn),由于與本文的內(nèi)容由很大的重復(fù),因此本文不再贅述上述相關(guān)內(nèi)容。
本文將會(huì)講解一些runtime
操作屬性的相關(guān)方法。
首先回顧一下相關(guān)代碼以及與property
底層實(shí)現(xiàn)相關(guān)的兩個(gè)結(jié)構(gòu)體:
//OC自定義類(lèi)的定義
@interface Person : NSObject
@property (nonatomic, copy) NSString* cjmName;
@property (nonatomic, assign) NSUInteger cjmAge;
@end
@implementation Person
@synthesize cjmName = _cjmName;
@synthesize cjmAge = _cjmAge;
@end
//clang轉(zhuǎn)寫(xiě)為.cpp的相關(guān)代碼
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"}}
};
通過(guò)上述代碼其實(shí)我們可以看出,一個(gè)@property
屬性在底層就是一個(gè)結(jié)構(gòu)體描述,那么我們?nèi)绾潍@取這個(gè)結(jié)構(gòu)體呢?可以通過(guò)如下代碼獲取:
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
中可以找到相關(guān)定義:
typedef struct objc_property *objc_property_t;
它是一個(gè)指向結(jié)構(gòu)體struct objc_property
的指針,這里的結(jié)構(gòu)體struct objc_property
其實(shí)就是前文中.cpp
文件中的struct _prop_t
結(jié)構(gòu)體,通過(guò)class_copyPropertyList
方法就可以獲取到相關(guān)類(lèi)的所有屬性,具體函數(shù)聲明如下:
/**
* 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);
通過(guò)注釋可以看出,第一個(gè)參數(shù)是相關(guān)類(lèi)的類(lèi)對(duì)象(如有疑問(wèn)可以查閱本系列文章的前兩篇文章),第二個(gè)參數(shù)是一個(gè)指向unsigned int
的指針,用于指明property
的數(shù)量,通過(guò)該方法就能夠獲取到所有的屬性,接下來(lái)可以通過(guò)property_getName
和property_getAttributes
方法獲取該屬性描述的name
和attributes
值,輸出的結(jié)果如下:
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
通過(guò)對(duì)比不難發(fā)現(xiàn)其規(guī)律,感興趣的讀者也可以多設(shè)置幾個(gè)不同類(lèi)型、不同修飾符的property
看一下輸出。
除此之外哈有一下幾個(gè)方法用于根據(jù)屬性名獲取一個(gè)屬性描述結(jié)構(gòu)體、添加屬性、替換屬性等方法。
/**
* 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);
舉個(gè)簡(jiǎn)單的栗子:
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;
}
通過(guò)上述方法就能添加一個(gè)屬性,由于本人水平有限實(shí)際開(kāi)發(fā)中沒(méi)有用過(guò)上述方法,具體實(shí)際例子也舉不出來(lái)所以不再過(guò)多贅述。
備注
由于作者水平有限,難免出現(xiàn)紕漏,如有問(wèn)題還請(qǐng)不吝賜教。