Получить список свойств объекта в Objective-C
Как я могу получить список (в форме NSArray
или же NSDictionary
) атрибутов данного объекта в Objective-C?
Представьте себе следующий сценарий: я определил родительский класс, который просто расширяет NSObject
, который держит NSString
, BOOL
и NSData
объект как атрибуты. Затем у меня есть несколько классов, которые расширяют этот родительский класс, добавляя множество различных атрибутов каждый.
Есть ли способ, которым я мог бы реализовать метод экземпляра в родительском классе, который проходит через весь объект и возвращает, скажем, NSArray
каждого из (дочерних) атрибутов класса как NSStrings
которые не находятся в родительском классе, поэтому я могу позже использовать эти NSString
для КВК?
13 ответов
Мне просто удалось получить ответ сам. Используя библиотеку времени выполнения 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);
}
Это потребовало от меня создания C-функции 'getPropertyType', которая в основном взята из примера кода 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 "@";
}
Ответ @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
Ответ @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
Когда я пытался с 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);
Я обнаружил, что решение Boliva отлично работает в симуляторе, но на устройстве подстрока фиксированной длины вызывает проблемы. Я написал более подходящее для Objective-C решение этой проблемы, которое работает на устройстве. В моей версии я преобразую C-строку атрибутов в строку 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;
}
Эта реализация работает как с объектными типами Objective-C, так и с примитивами C. Это совместимо с iOS 8. Этот класс предоставляет три метода класса:
+ (NSDictionary *) propertiesOfObject:(id)object;
Возвращает словарь всех видимых свойств объекта, включая свойства всех его суперклассов.
+ (NSDictionary *) propertiesOfClass:(Class)class;
Возвращает словарь всех видимых свойств класса, включая свойства всех его суперклассов.
+ (NSDictionary *) propertiesOfSubclass:(Class)class;
Возвращает словарь всех видимых свойств, относящихся к подклассу. Свойства для его суперклассов не включены.
Одним из полезных примеров использования этих методов является копирование объекта в экземпляр подкласса в Objective-C без необходимости указывать свойства в методе копирования. Части этого ответа основаны на других ответах на этот вопрос, но он обеспечивает более чистый интерфейс для желаемой функциональности.
Заголовок:
// 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
Если кому-то также нужно получить свойства, унаследованные от родительских классов (как я это сделал), вот некоторая модификация кода " 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];
}
}
Я смог получить ответ @orange80 для работы с ARC ENABLED...... для того, что я хотел - по крайней мере... но не без проб и ошибок. Надеюсь, эта дополнительная информация может избавить кого-то от горя.
Сохраните те классы, которые он описывает в своем ответе = как класс, и в своем 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;
}
Несмотря на то, что Apple беззастенчиво / OCD хвастается интроспекцией ObjC "amazeballs"... Они, конечно, не позволяют легко выполнить этот простой "взгляд" "на себя", "так сказать"..
Если вы действительно хотите свихнуться, хотя... проверьте... class-dump, который является ошеломляющим безумным способом заглянуть в заголовки классов ЛЮБОГО исполняемого файла и т. Д.... Он обеспечивает VERBOSE взгляд на ваши классы... что я, лично, найти действительно полезным - во многих, многих обстоятельствах. Именно поэтому я начал искать решение вопроса ОП. Вот некоторые параметры использования.. наслаждайтесь!
-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
У вас есть три магических заклинания
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);
}
Слово "атрибуты" немного нечетко. Вы имеете в виду переменные экземпляра, свойства, методы, которые выглядят как методы доступа?
Ответ на все три вопроса - "да, но это не очень легко". API времени выполнения Objective C включает функции для получения списка ivar, списка методов или списка свойств для класса (например, class_copyPropertyList()
), а затем соответствующую функцию для каждого типа, чтобы получить имя элемента в списке (например, property_getName()
).
В целом, чтобы сделать это правильно, может потребоваться много работы, или, по крайней мере, намного больше, чем хотелось бы большинству людей, что обычно составляет действительно тривиальную функцию.
В качестве альтернативы, вы можете просто написать скрипт на Ruby/Python, который просто читает заголовочный файл и ищет все, что вы считаете "атрибутами" для класса.
Для наблюдателей 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"
Я использовал функцию boliva, но, по-видимому, она перестала работать с iOS 7. Поэтому теперь вместо статического const char *getPropertyType(свойство objc_property_t) можно просто использовать следующее:
- (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:@""];
}
Эти ответы полезны, но мне нужно больше от этого. Все, что я хочу сделать, это проверить, равен ли тип класса свойства существующему объекту. Все приведенные выше коды не способны сделать это, потому что: Чтобы получить имя класса объекта, 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(...) из приведенного выше примера кода, то wit 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;
}