獲取Objective-C中的對象屬性列表如何在Objective-C中獲取給定對象屬性的列表(以NSArray或的形式NSDictionary)?想象一下下面的場景:我已經定義了一個只擴展的父類NSObject,它將a NSString,a BOOL和一個NSData對象作為屬性。然后我有幾個擴展這個父類的類,每個類都添加了很多不同的屬性。有沒有什么方法可以在父類上實現一個遍歷整個對象的實例方法,然后返回NSArray每個(子)類屬性的一個,因為NSStrings它不在父類上,所以我以后可以使用這些NSString對于KVC?
3 回答
拉丁的傳說
TA貢獻1789條經驗 獲得超8個贊
我自己設法得到了答案。通過使用Obj-C運行時庫,我可以按照我想要的方式訪問屬性:
- (void)myMethod {
unsigned int outCount, i;
objc_property_t *properties = class_copyPropertyList([self class], &outCount);
for(i = 0; i < outCount; i++) {
objc_property_t property = properties[i];
const char *propName = property_getName(property);
if(propName) {
const char *propType = getPropertyType(property);
NSString *propertyName = [NSString stringWithCString:propName
encoding:[NSString defaultCStringEncoding]];
NSString *propertyType = [NSString stringWithCString:propType
encoding:[NSString defaultCStringEncoding]];
...
}
}
free(properties);}這要求我制作一個'getPropertyType'C函數,它主要取自Apple代碼示例(現在不能記住確切的來源):
static const char *getPropertyType(objc_property_t property) {
const char *attributes = property_getAttributes(property);
char buffer[1 + strlen(attributes)];
strcpy(buffer, attributes);
char *state = buffer, *attribute;
while ((attribute = strsep(&state, ",")) != NULL) {
if (attribute[0] == 'T') {
if (strlen(attribute) <= 4) {
break;
}
return (const char *)[[NSData dataWithBytes:(attribute + 3) length:strlen(attribute) - 4] bytes];
}
}
return "@";}
明月笑刀無情
TA貢獻1828條經驗 獲得超4個贊
它實際上并不總是以0結束字符串。這可能會導致意外的結果,比如在嘗試將其轉換為UTF8時崩潰(我實際上有一個非常令人討厭的崩潰因為這個。很有趣的調試它^^)。我通過實際從屬性獲取NSString然后調用cStringUsingEncoding來修復它:這就像現在的魅力。(也適用于ARC,至少對我而言)
所以這是我現在的代碼版本:
// PropertyUtil.h#import @interface PropertyUtil : NSObject+ (NSDictionary *)classPropsFor:(Class)klass;@end// PropertyUtil.m#import "PropertyUtil.h"#import <objc/runtime.h>@implementation PropertyUtilstatic const char *getPropertyType(objc_property_t property) {
const char *attributes = property_getAttributes(property);
//printf("attributes=%s\n", attributes);
char buffer[1 + strlen(attributes)];
strcpy(buffer, attributes);
char *state = buffer, *attribute;
while ((attribute = strsep(&state, ",")) != NULL) {
if (attribute[0] == 'T' && attribute[1] != '@') {
// it's a C primitive type:
/*
if you want a list of what will be returned for these primitives, search online for
"objective-c" "Property Attribute Description Examples"
apple docs list plenty of examples of what you get for int "i", long "l", unsigned "I", struct, etc.
*/
NSString *name = [[NSString alloc] initWithBytes:attribute + 1 length:strlen(attribute) - 1 encoding:NSASCIIStringEncoding];
return (const char *)[name cStringUsingEncoding:NSASCIIStringEncoding];
}
else if (attribute[0] == 'T' && attribute[1] == '@' && strlen(attribute) == 2) {
// it's an ObjC id type:
return "id";
}
else if (attribute[0] == 'T' && attribute[1] == '@') {
// it's another ObjC object type:
NSString *name = [[NSString alloc] initWithBytes:attribute + 3 length:strlen(attribute) - 4 encoding:NSASCIIStringEncoding];
return (const char *)[name cStringUsingEncoding:NSASCIIStringEncoding];
}
}
return "";}+ (NSDictionary *)classPropsFor:(Class)klass{
if (klass == NULL) {
return nil;
}
NSMutableDictionary *results = [[NSMutableDictionary alloc] init];
unsigned int outCount, i;
objc_property_t *properties = class_copyPropertyList(klass, &outCount);
for (i = 0; i < outCount; i++) {
objc_property_t property = properties[i];
const char *propName = property_getName(property);
if(propName) {
const char *propType = getPropertyType(property);
NSString *propertyName = [NSString stringWithUTF8String:propName];
NSString *propertyType = [NSString stringWithUTF8String:propType];
[results setObject:propertyType forKey:propertyName];
}
}
free(properties);
// returning a copy here to make sure the dictionary is immutable
return [NSDictionary dictionaryWithDictionary:results];}@end- 3 回答
- 0 關注
- 702 瀏覽
添加回答
舉報
0/150
提交
取消
