在 Objective-C 中获取对象属性列表
Posted
技术标签:
【中文标题】在 Objective-C 中获取对象属性列表【英文标题】:Get an object properties list in Objective-C 【发布时间】:2010-10-19 18:46:50 【问题描述】:如何在 Objective-C 中获取给定对象属性的列表(以NSArray
或NSDictionary
的形式)?
想象以下场景:我定义了一个父类,它只是扩展了NSObject
,它包含一个NSString
、一个BOOL
和一个NSData
对象作为属性。然后我有几个类扩展了这个父类,每个类都添加了很多不同的属性。
有什么方法可以在 parent 类上实现一个实例方法,该方法遍历整个对象并返回,例如,每个(子)类属性的NSArray
作为@ 987654328@ 不在父类上,所以我以后可以将这些NSString
用于 KVC?
【问题讨论】:
【参考方案1】:“属性”这个词有点模糊。您是指看起来像访问器的实例变量、属性、方法吗?
这三个问题的答案都是“是的,但这并不容易”。 Objective-C runtime API 包括用于获取类的 ivar 列表、方法列表或属性列表的函数(例如,class_copyPropertyList()
),然后是每种类型的相应函数以获取列表中项目的名称(例如,@ 987654323@)。
总而言之,要做到这一点可能需要做很多工作,或者至少比大多数人想要做的事情要多得多,因为这通常相当于一个非常微不足道的功能。
或者,您可以编写一个 Ruby/Python 脚本,该脚本仅读取头文件并查找您认为类的“属性”。
【讨论】:
嗨查克,感谢您的回复。我所说的“属性”确实是指类属性。通过使用 Obj-C 运行时库,我已经设法完成了我想要的。使用脚本来解析头文件对于我在运行时需要的东西不起作用。【参考方案2】:我自己设法得到了答案。通过使用 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 "@";
【讨论】:
+1 除非这会在原语上出错,例如 int。请在下面查看我的答案,以了解同一事物的略微增强版本。 为了正确起见,[NSString stringWithCString:]
被[NSString stringWithCString:encoding:]
取代。
应该导入 objc 运行时标头 #import 当我尝试使用 ios 3.2 时,getPropertyType 函数不能很好地与属性描述配合使用。我从 iOS 文档中找到了一个示例:“Objective-C 运行时编程指南:声明的属性”。
这是 iOS 3.2 中属性列表的修改代码:
#import <objc/runtime.h>
#import <Foundation/Foundation.h>
...
unsigned int outCount, i;
objc_property_t *properties = class_copyPropertyList([UITouch class], &outCount);
for(i = 0; i < outCount; i++)
objc_property_t property = properties[i];
fprintf(stdout, "%s %s\n", property_getName(property), property_getAttributes(property));
free(properties);
【讨论】:
【参考方案4】:@boliva 的回答很好,但需要一些额外的东西来处理原语,如 int、long、float、double 等。
我在他的基础上添加了这个功能。
// PropertyUtil.h
#import
@interface PropertyUtil : NSObject
+ (NSDictionary *)classPropsFor:(Class)klass;
@end
// PropertyUtil.m
#import "PropertyUtil.h"
#import "objc/runtime.h"
@implementation PropertyUtil
static 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.
*/
return (const char *)[[NSData dataWithBytes:(attribute + 1) length:strlen(attribute) - 1] bytes];
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:
return (const char *)[[NSData dataWithBytes:(attribute + 3) length:strlen(attribute) - 4] bytes];
return "";
+ (NSDictionary *)classPropsFor:(Class)klass
if (klass == NULL)
return nil;
NSMutableDictionary *results = [[[NSMutableDictionary alloc] init] autorelease];
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
【讨论】:
您是否打算将#import <Foundation/Foundation.h>
放在 .h 文件的顶部?
[NSString stringWithUTF8String:propType] 无法解析 "propType const char * "NSNumber\x94\xfdk;" 并返回一个 nil 字符串...不知道为什么它是一个奇怪的 NSNumber . Mb 因为 ActiveRecord?
太棒了!非常感谢。
这绝对是完美的!【参考方案5】:
我能够得到@orange80 的回答,启用 ARC……我想要的 - 至少……但并非没有一点试错。希望这些额外的信息可以减轻别人的痛苦。
将those classes he describes in his answer = 保存为一个类,并在您的AppDelegate.h
(或其他)中输入#import PropertyUtil.h
。然后在你的...
- (void)applicationDidFinishLaunching:
(NSNotification *)aNotification
方法(或其他)
…
PropertyUtil *props = [PropertyUtil new];
NSDictionary *propsD = [PropertyUtil classPropsFor:
(NSObject*)[gist class]];
NSLog(@"%@, %@", props, propsD);
…
秘诀是转换你想要查询的类的实例变量(在这种情况下,我的类是Gist
,我的Gist
实例是gist
)。 .. 到 NSObject...(id)
等,不会削减它.. 出于各种、奇怪、深奥的原因。这会给你一些像这样的输出......
<PropertyUtil: 0x7ff0ea92fd90>,
apiURL = NSURL;
createdAt = NSDate;
files = NSArray;
gistDescription = NSString;
gistId = NSString;
gitPullURL = NSURL;
gitPushURL = NSURL;
htmlURL = NSURL;
isFork = c;
isPublic = c;
numberOfComments = Q;
updatedAt = NSDate;
userLogin = NSString;
对于所有苹果公司毫不掩饰/强迫症吹嘘 ObjC 的“惊奇球”“内省......他们肯定不会让执行这种简单的“看”“自我”,“可以这么说”变得很容易......
如果你真的想去疯狂..看看..class-dump,这是一种令人难以置信的疯狂方式来查看任何可执行文件的类头等......它提供详细了解您的课程……我个人认为在很多很多情况下确实很有帮助。这实际上就是为什么我开始寻求解决 OP 问题的原因。这是一些使用参数..享受!
-a show instance variable offsets
-A show implementation addresses
--arch <arch> choose a specific architecture from a universal binary (ppc, ppc64, i386, x86_64)
-C <regex> only display classes matching regular expression
-f <str> find string in method name
-I sort classes, categories, and protocols by inheritance (overrides -s)
-r recursively expand frameworks and fixed VM shared libraries
-s sort classes and categories by name
-S sort methods by name
【讨论】:
【参考方案6】:我发现 boliva 的解决方案在模拟器中运行良好,但在设备上,固定长度的子字符串会导致问题。我已经为这个问题写了一个对 Objective-C 更友好的解决方案,它可以在设备上运行。在我的版本中,我将属性的 C-String 转换为 NSString 并对其执行字符串操作以获取仅包含类型描述的子字符串。
/*
* @returns A string describing the type of the property
*/
+ (NSString *)propertyTypeStringOfProperty:(objc_property_t) property
const char *attr = property_getAttributes(property);
NSString *const attributes = [NSString stringWithCString:attr encoding:NSUTF8StringEncoding];
NSRange const typeRangeStart = [attributes rangeOfString:@"T@\""]; // start of type string
if (typeRangeStart.location != NSNotFound)
NSString *const typeStringWithQuote = [attributes substringFromIndex:typeRangeStart.location + typeRangeStart.length];
NSRange const typeRangeEnd = [typeStringWithQuote rangeOfString:@"\""]; // end of type string
if (typeRangeEnd.location != NSNotFound)
NSString *const typeString = [typeStringWithQuote substringToIndex:typeRangeEnd.location];
return typeString;
return nil;
/**
* @returns (NSString) Dictionary of property name --> type
*/
+ (NSDictionary *)propertyTypeDictionaryOfClass:(Class)klass
NSMutableDictionary *propertyMap = [NSMutableDictionary dictionary];
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)
NSString *propertyName = [NSString stringWithCString:propName encoding:NSUTF8StringEncoding];
NSString *propertyType = [self propertyTypeStringOfProperty:property];
[propertyMap setValue:propertyType forKey:propertyName];
free(properties);
return propertyMap;
【讨论】:
这会在 NSRange 上抛出 EXC_BAD_ACCESS 异常 const typeRangeStart = [attributes rangeOfString:@"T@\""]; // 字符串类型的开始【参考方案7】:@orange80 的回答有一个问题:它实际上并不总是以 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 PropertyUtil
static 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
【讨论】:
@farthen 你能提供一个例子来演示我提供的代码的问题吗?我只是想看看它。 @orange80 好吧,AFAIR 数据永远不会以零结尾。如果是这样,这只会发生在意外情况下。不过我可能是错的。在其他新闻中:我仍然在运行此代码并且它运行稳定:p @orange80 我在尝试从谷歌的 IMA 广告库中调用您的 IMAAdRequest 版本时遇到了这个问题。 farthen 的解决方案解决了它。 谢谢。当前两个答案没有时,这在 iOS7 中对我有用。所有 3 人 +1。 这是唯一对我有用的答案。其他所有东西都给了我类似“NSString\x8d\xc0\xd9”属性类型的怪异,大概是因为 char* 大小已关闭【参考方案8】:我使用的是提供的 boliva 函数,但显然它在 iOS 7 中停止工作。所以现在可以使用以下命令代替 static const char *getPropertyType(objc_property_t property):
- (NSString*) classOfProperty:(NSString*)propName
objc_property_t prop = class_getProperty([self class], [propName UTF8String]);
if (!prop)
// doesn't exist for object
return nil;
const char * propAttr = property_getAttributes(prop);
NSString *propString = [NSString stringWithUTF8String:propAttr];
NSArray *attrArray = [propString componentsSeparatedByString:@","];
NSString *class=[attrArray objectAtIndex:0];
return [[class stringByReplacingOccurrencesOfString:@"\"" withString:@""] stringByReplacingOccurrencesOfString:@"T@" withString:@""];
【讨论】:
你是我的英雄。我仍然需要手动更正一些事情(由于某种原因,BOOL 会显示为“Tc”),但这实际上让我可以让事情再次正常运行。 基元有自己的类型,“@”表示对象,在它之后,类名出现在引号之间。唯一的例外是 id,它被简单地编码为“T@”【参考方案9】:如果有人也需要从父类继承的属性(就像我做的那样)这里是对“orange80”代码的一些修改使其递归:
+ (NSDictionary *)classPropsForClassHierarchy:(Class)klass onDictionary:(NSMutableDictionary *)results
if (klass == NULL)
return nil;
//stop if we reach the NSObject class as is the base class
if (klass == [NSObject class])
return [NSDictionary dictionaryWithDictionary:results];
else
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);
//go for the superclass
return [PropertyUtil classPropsForClassHierarchy:[klass superclass] onDictionary:results];
【讨论】:
我们不能把它变成一个类别并用它扩展 NSObject,这样这个功能就内置到每个 NSObject 的子类中了吗? 这听起来是个好主意,如果我能找到时间将使用该选项更新答案。 一旦你完成了,我会在有时间的时候添加一个方法转储。是时候在每个 NSObject 之上获得真正的对象属性和方法自省了。 我也一直在努力增加值输出,但似乎对于某些结构(矩形),类型是属性的实际值。 tableViewController 的 caretRect 和 viewController 结构中的其他无符号整数就是这种情况,返回 c 或 f 作为与 Objective-C 运行时文档冲突的类型。显然,这里需要做更多的工作才能完成。 developer.apple.com/library/mac/documentation/cocoa/conceptual/… 我正在查看,但有一个问题我无法解决,为了使其递归,我需要调用超类的方法(如上一个代码的最后一行),因为 NSObject 是不能在类别中工作的根类。所以不可能有递归...... :( 不确定 NSObject 中的一个类别是否是可行的方法......【参考方案10】:此实现适用于 Objective-C 对象类型和 C 原语。它与 iOS 8 兼容。该类提供了三个类方法:
+ (NSDictionary *) propertiesOfObject:(id)object;
返回对象所有可见属性的字典,包括来自其所有超类的属性。
+ (NSDictionary *) propertiesOfClass:(Class)class;
返回一个类的所有可见属性的字典,包括其所有超类的属性。
+ (NSDictionary *) propertiesOfSubclass:(Class)class;
返回一个包含特定子类的所有可见属性的字典。 不包括其超类的属性。
使用这些方法的一个有用示例是copy an object to a subclass instance in Objective-C without having to specify the properties in a copy method。此答案的部分内容基于此问题的其他答案,但它为所需功能提供了更简洁的界面。
标题:
// SYNUtilities.h
#import <Foundation/Foundation.h>
@interface SYNUtilities : NSObject
+ (NSDictionary *) propertiesOfObject:(id)object;
+ (NSDictionary *) propertiesOfClass:(Class)class;
+ (NSDictionary *) propertiesOfSubclass:(Class)class;
@end
实施:
// SYNUtilities.m
#import "SYNUtilities.h"
#import <objc/objc-runtime.h>
@implementation SYNUtilities
+ (NSDictionary *) propertiesOfObject:(id)object
Class class = [object class];
return [self propertiesOfClass:class];
+ (NSDictionary *) propertiesOfClass:(Class)class
NSMutableDictionary * properties = [NSMutableDictionary dictionary];
[self propertiesForHierarchyOfClass:class onDictionary:properties];
return [NSDictionary dictionaryWithDictionary:properties];
+ (NSDictionary *) propertiesOfSubclass:(Class)class
if (class == NULL)
return nil;
NSMutableDictionary *properties = [NSMutableDictionary dictionary];
return [self propertiesForSubclass:class onDictionary:properties];
+ (NSMutableDictionary *)propertiesForHierarchyOfClass:(Class)class onDictionary:(NSMutableDictionary *)properties
if (class == NULL)
return nil;
if (class == [NSObject class])
// On reaching the NSObject base class, return all properties collected.
return properties;
// Collect properties from the current class.
[self propertiesForSubclass:class onDictionary:properties];
// Collect properties from the superclass.
return [self propertiesForHierarchyOfClass:[class superclass] onDictionary:properties];
+ (NSMutableDictionary *) propertiesForSubclass:(Class)class onDictionary:(NSMutableDictionary *)properties
unsigned int outCount, i;
objc_property_t *objcProperties = class_copyPropertyList(class, &outCount);
for (i = 0; i < outCount; i++)
objc_property_t property = objcProperties[i];
const char *propName = property_getName(property);
if(propName)
const char *propType = getPropertyType(property);
NSString *propertyName = [NSString stringWithUTF8String:propName];
NSString *propertyType = [NSString stringWithUTF8String:propType];
[properties setObject:propertyType forKey:propertyName];
free(objcProperties);
return properties;
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' && attribute[1] != '@')
// A C primitive type:
/*
For example, int "i", long "l", unsigned "I", struct.
Apple docs list plenty of examples of values returned. For a list
of what will be returned for these primitives, search online for
"Objective-c" "Property Attribute Description Examples"
*/
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)
// An Objective C id type:
return "id";
else if (attribute[0] == 'T' && attribute[1] == '@')
// Another Objective C id type:
NSString *name = [[NSString alloc] initWithBytes:attribute + 3 length:strlen(attribute) - 4 encoding:NSASCIIStringEncoding];
return (const char *)[name cStringUsingEncoding:NSASCIIStringEncoding];
return "";
@end
【讨论】:
我在这一行得到一个 EXC_BAD_ACCESS 异常 NSString *name = [[NSString alloc] initWithBytes:attribute + 1 length:strlen(attribute) - 1 encoding:NSASCIIStringEncoding];【参考方案11】:这些答案很有帮助,但我需要更多。我要做的就是检查属性的类类型是否等于现有对象的类类型。上面的所有代码都不能这样做,因为: 要获取对象的类名,object_getClassName() 返回如下文本:
__NSArrayI (for an NSArray instance)
__NSArrayM (for an NSMutableArray instance)
__NSCFBoolean (an NSNumber object initialized by initWithBool:)
__NSCFNumber (an NSValue object initialized by [NSNumber initWithBool:])
但是如果从上面的示例代码中调用 getPropertyType(...),那么定义的类的属性的 4 个 objc_property_t 结构如下:
@property (nonatomic, strong) NSArray* a0;
@property (nonatomic, strong) NSArray* a1;
@property (nonatomic, copy) NSNumber* n0;
@property (nonatomic, copy) NSValue* n1;
分别返回如下字符串:
NSArray
NSArray
NSNumber
NSValue
因此它无法确定 NSObject 是否能够成为该类的一个属性的值。那该怎么做呢?
这是我的完整示例代码(函数 getPropertyType(...) 与上面相同):
#import <objc/runtime.h>
@interface FOO : NSObject
@property (nonatomic, strong) NSArray* a0;
@property (nonatomic, strong) NSArray* a1;
@property (nonatomic, copy) NSNumber* n0;
@property (nonatomic, copy) NSValue* n1;
@end
@implementation FOO
@synthesize a0;
@synthesize a1;
@synthesize n0;
@synthesize n1;
@end
static 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 "";
int main(int argc, char * argv[])
NSArray* a0 = [[NSArray alloc] init];
NSMutableArray* a1 = [[NSMutableArray alloc] init];
NSNumber* n0 = [[NSNumber alloc] initWithBool:YES];
NSValue* n1 = [[NSNumber alloc] initWithBool:NO];
const char* type0 = object_getClassName(a0);
const char* type1 = object_getClassName(a1);
const char* type2 = object_getClassName(n0);
const char* type3 = object_getClassName(n1);
objc_property_t property0 = class_getProperty(FOO.class, "a0");
objc_property_t property1 = class_getProperty(FOO.class, "a1");
objc_property_t property2 = class_getProperty(FOO.class, "n0");
objc_property_t property3 = class_getProperty(FOO.class, "n1");
const char * memberthype0 = getPropertyType(property0);//property_getAttributes(property0);
const char * memberthype1 = getPropertyType(property1);//property_getAttributes(property1);
const char * memberthype2 = getPropertyType(property2);//property_getAttributes(property0);
const char * memberthype3 = getPropertyType(property3);//property_getAttributes(property1);
NSLog(@"%s", type0);
NSLog(@"%s", type1);
NSLog(@"%s", type2);
NSLog(@"%s", type3);
NSLog(@"%s", memberthype0);
NSLog(@"%s", memberthype1);
NSLog(@"%s", memberthype2);
NSLog(@"%s", memberthype3);
return 0;
【讨论】:
【参考方案12】:你有三个魔法咒语
Ivar* ivars = class_copyIvarList(clazz, &count); // to get all iVars
objc_property_t *properties = class_copyPropertyList(clazz, &count); //to get all properties of a class
Method* methods = class_copyMethodList(clazz, &count); // to get all methods of a class.
下面的代码可以帮助你。
-(void) displayClassInfo
Class clazz = [self class];
u_int count;
Ivar* ivars = class_copyIvarList(clazz, &count);
NSMutableArray* ivarArray = [NSMutableArray arrayWithCapacity:count];
for (int i = 0; i < count ; i++)
const char* ivarName = ivar_getName(ivars[i]);
ivarArray addObject:[NSString stringWithCString:ivarName encoding:NSUTF8StringEncoding]];
free(ivars);
objc_property_t* properties = class_copyPropertyList(clazz, &count);
NSMutableArray* propertyArray = [NSMutableArray arrayWithCapacity:count];
for (int i = 0; i < count ; i++)
const char* propertyName = property_getName(properties[i]);
[propertyArray addObject:[NSString stringWithCString:propertyName encoding:NSUTF8StringEncoding]];
free(properties);
Method* methods = class_copyMethodList(clazz, &count);
NSMutableArray* methodArray = [NSMutableArray arrayWithCapacity:count];
for (int i = 0; i < count ; i++)
SEL selector = method_getName(methods[i]);
const char* methodName = sel_getName(selector);
[methodArray addObject:[NSString stringWithCString:methodName encoding:NSUTF8StringEncoding]];
free(methods);
NSDictionary* classInfo = [NSDictionary dictionaryWithObjectsAndKeys:
ivarArray, @"ivars",
propertyArray, @"properties",
methodArray, @"methods",
nil];
NSLog(@"%@", classInfo);
【讨论】:
【参考方案13】:对于 Swift 旁观者,您可以通过使用 Encodable
功能获得此功能。我将解释如何:
使您的对象符合Encodable
协议
class ExampleObj: NSObject, Encodable
var prop1: String = ""
var prop2: String = ""
为Encodable
创建扩展以提供toDictionary
功能
public func toDictionary() -> [String: AnyObject]?
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
guard let data = try? encoder.encode(self),
let json = try? JSONSerialization.jsonObject(with: data, options: .init(rawValue: 0)), let jsonDict = json as? [String: AnyObject] else
return nil
return jsonDict
在您的对象实例上调用 toDictionary
并访问 keys
属性。
let exampleObj = ExampleObj()
exampleObj.toDictionary()?.keys
瞧!像这样访问您的属性:
for k in exampleObj!.keys
print(k)
// Prints "prop1"
// Prints "prop2"
【讨论】:
以上是关于在 Objective-C 中获取对象属性列表的主要内容,如果未能解决你的问题,请参考以下文章
一个Objective-C对象如何进行内存布局?(考虑有父类的情况)