Objective-C动态获取实例属性

2014-09-13 Xiaosong Gao 更多博文 » 博客 » GitHub »

iOS Mac

原文链接 https://gaoxiaosong.github.io/2014/09/13/objective-c-get-properties.html
注:以下为加速网络访问所做的原文缓存,经过重新格式化,可能存在格式方面的问题,或偶有遗漏信息,请以原文为准。


本文主题是如何动态获取实例属性的值。

Objective-C运行时库已经有这样的功能。使用这些方法需要加头文件。

#import <objc/message.h>

要用到的方法是:

objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount)

从方法的名字可以看出作用:将一个类的属性copy出来。下面看一个例子,就知道如何使用了。

@interface People : NSObject
@property NSString *name;
@end

现在我们动态获取它的属性名,与实例属性值。

People *people = [[People alloc] init];
id peopleClass = objc_getClass("People");
unsigned int outCount, i;
objc_property_t *properties = class_copyPropertyList(peopleClass, &outCount);
for (i = 0; i < outCount; i++) {
  objc_property_t property = properties[i];
  NSString *propName = [NSString stringWithUTF8String:property_getName(property)];
  id value = [people valueForKey:propName];
  fprintf(stdout, "%s %s\n", property_getName(property), property_getAttributes(property));
}

这样一来就可以获取所有的属性值。比如格式化对像为JSON或XML的时候就很有用。

但是如果类从其它的类继承过来的,父类的属性将不会被copy出来。如

@interface People : NSObject
@property NSString *name;
@end

@interface Lender : People
@property int employers;
@end

Lender *leader = [[People alloc] init];
id leaderClass = objc_getClass("Lender");
unsigned int outCount, i;
objc_property_t *properties = class_copyPropertyList(leaderClass, &outCount);
for (i = 0; i < outCount; i++) {
  objc_property_t property = properties[i];
  NSString *propName = [NSString stringWithUTF8String:property_getName(property)];
  id value = [leader valueForKey:propName];
  fprintf(stdout, "%s %s\n", property_getName(property), property_getAttributes(property));
}

这儿可能获取employers的属性的值,如何才能获取到父类的属性呢。

有两种方法。

  1. 用前面提到的方法分别获取子类与父类的属性列表。
  2. 声明一个Protocol, Protocol中有属性,然后获取Protocol中属性列表。

第二个方法中要用到两个方法:

objc_property_t *protocol_copyPropertyList(Protocol *proto, unsigned int *outCount)
Protocol *objc_getProtocol(const char *name)

用法与前面掉到的都差不多。