Получить список свойств объекта в Objective-C

Как я могу получить список (в форме NSArray или NSDictionary) заданных атрибутов объекта в Objective-C?

Представьте себе следующий сценарий: я определил родительский класс, который просто расширяет NSObject, который содержит объекты NSString, a BOOL и NSData в качестве атрибутов. Затем у меня есть несколько классов, которые расширяют этот родительский класс, добавляя много разных атрибутов.

Можно ли каким-либо образом реализовать метод экземпляра родительского класса, который проходит через весь объект и возвращает, скажем, NSArray каждого из атрибутов класса (дочернего) как NSStrings, которые не находятся на родительский класс, поэтому я могу позже использовать эти NSString для KVC?

Ответ 1

Мне просто удалось получить ответ сам. Используя библиотеку времени выполнения 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 "@";
}

Ответ 2

@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 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 an ObjC id type:
            return "id";
        }
        else if (attribute[0] == 'T' && attribute[1] == '@') {
            // it 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

Ответ 3

@orange80 ответ имеет одну проблему: он на самом деле не всегда заканчивает строку с 0s. Это может привести к неожиданным результатам, например, сбоям при попытке конвертировать его в UTF8 (у меня на самом деле был довольно раздражающий crashbug именно из-за этого. Было весело отлаживать его ^^). Я исправил это, фактически получив 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 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 an ObjC id type:
            return "id";
        }
        else if (attribute[0] == 'T' && attribute[1] == '@') {
            // it 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

Ответ 4

Когда я попытался с 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);

Ответ 5

Я обнаружил, что решение 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:@"[email protected]\""];  // 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;
}

Ответ 6

Эта реализация работает как с типами объектов 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

Ответ 7

Я смог получить ответ @orange80 на работу WITH 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 просмотр ваших классов... что я лично считаю действительно полезным - во многих и многих обстоятельствах. на самом деле, почему я начал искать решение вопроса 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

Ответ 8

Если кто-то нуждается в получении свойств, унаследованных от родительских классов (как и я), здесь есть некоторые изменения в " 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];

    }
}

Ответ 9

Слово "атрибуты" немного нечеткое. Вы имеете в виду переменные экземпляра, свойства, методы, которые выглядят как аксессоры?

Ответ всем трем - "да, но это не очень легко". Objective-C API среды выполнения включает функции для получения списка ivar, списка методов или списка свойств для класса (например, class_copyPropertyList()), а затем соответствующую функцию для каждого типа, чтобы получить имя элемента в списке (например, property_getName()).

В целом, это может быть довольно много работы, чтобы понять это правильно, или, по крайней мере, намного больше, чем большинство людей хотели бы сделать для того, что обычно представляет собой действительно тривиальную функцию.

В качестве альтернативы вы можете просто написать Ruby/Python script, который просто читает заголовочный файл и ищет все, что вы считаете "атрибутами" для этого класса.

Ответ 10

Я использовал функцию 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:@"[email protected]" withString:@""];
}

Ответ 11

У вас есть три магических заклинания

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);
}

Ответ 12

Эти ответы полезны, но я требую от этого большего. Все, что я хочу сделать, это проверить, соответствует ли тип класса свойства объекту существующего объекта. Все приведенные выше коды не способны сделать это, потому что: Чтобы получить имя класса объекта, 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 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 an ObjC id type:
            return "id";
        }
        else if (attribute[0] == 'T' && attribute[1] == '@') {
            // it 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;
}