web-dev-qa-db-ja.com

Objective-Cでオブジェクトプロパティリストを取得する

Objective-Cの特定のオブジェクトプロパティのリスト(NSArrayまたはNSDictionaryの形式)を取得するにはどうすればよいですか?

以下のシナリオを想像してください。NSObjectNSString、およびBOOLオブジェクトをプロパティとして保持するNSDataを拡張するだけの親クラスを定義しました。次に、この親クラスを拡張する複数のクラスがあり、それぞれに多くの異なるプロパティを追加します。

クラスにインスタンスメソッドを実装する方法はありますか?これは、オブジェクト全体を通過し、たとえば、各(子)クラスプロパティのNSArrayNSStringsとして返しますnot親クラスで、後でこれらのNSStringをKVCに使用できますか?

107
boliva

私は自分で答えを得ることができました。 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);
}

そのため、主にAppleのコードサンプル(正確なソースを思い出せない))から取得した 'getPropertyType' C関数を作成する必要がありました。

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 "@";
}
115
boliva

@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

73
jpswain

@ orange80の答えには1つの問題があります。実際には、文字列が常に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
28
felinira

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);
8
Chatchavan

私は、ボリバのソリューションがシミュレータでうまく機能することを発見しましたが、デバイス上では固定長のサブストリングが問題を引き起こします。デバイスで動作するこの問題に対して、より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;
}

この実装は、Objective-CオブジェクトタイプとCプリミティブの両方で機能します。 iOS 8互換です。このクラスは、3つのクラスメソッドを提供します。

+ (NSDictionary *) propertiesOfObject:(id)object;

すべてのスーパークラスのプロパティを含む、オブジェクトのすべての可視プロパティのディクショナリを返します。

+ (NSDictionary *) propertiesOfClass:(Class)class;

すべてのスーパークラスのプロパティを含む、クラスのすべての表示プロパティのディクショナリを返します。

+ (NSDictionary *) propertiesOfSubclass:(Class)class;

サブクラスに固有のspecificであるすべての可視プロパティの辞書を返します。スーパークラスのプロパティはnot含まれています。

これらのメソッドを使用する便利な例の1つは、 copyメソッドでプロパティを指定せずにオブジェクトを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
6
Duncan Babbage

誰かが同様に取得する必要がある場合親クラスから継承されたプロパティ(私がやったように)ここに「orange8 "コードを再帰的にする:

+ (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];

    }
}
4
PakitoV

「属性」という言葉は少しあいまいです。インスタンス変数、プロパティ、アクセサーのように見えるメソッドを意味しますか?

3つすべての答えは「はい、しかしそれは非常に簡単ではありません」です。 Objective-CランタイムAPI には、クラスのivarリスト、メソッドリスト、またはプロパティリストを取得する関数(たとえば、class_copyPropertyList())が含まれています。リスト内のアイテムの名前を取得します(たとえば、property_getName())。

全体として、それを正しくするのは一種の多くの作業である場合があります。または、ほとんどの人が通常は本当に些細な機能に相当することを望んでいるよりも、少なくとも多くの作業があります。

または、ヘッダーファイルを読み取り、クラスの「属性」と見なすものを探すRuby/Pythonスクリプトを作成することもできます。

3
Chuck

@ 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)クエリしたい...to 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の「アマズボール」「内省」について自慢しています。

しかし、本当に独り占めしたい場合は、チェックアウトしてください..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
3
Alex Gray

あなたは3つの魔法の呪文を持っています

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

私は提供された関数bolivaを使用していましたが、どうやらiOS 7での動作が停止したようです。

- (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:@""];
}
2
Andrey Finayev

Swift=見物人の場合、Encodable機能を利用してこの機能を取得できます。

  1. オブジェクトをEncodableプロトコルに適合させます

    class ExampleObj: NSObject, Encodable {
        var prop1: String = ""
        var prop2: String = ""
    }
    
  2. 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
    }
    
  3. オブジェクトインスタンスでtoDictionaryを呼び出し、keysプロパティにアクセスします。

    let exampleObj = ExampleObj()
    exampleObj.toDictionary()?.keys
    
  4. 出来上がり!次のようにプロパティにアクセスします。

    for k in exampleObj!.keys {
        print(k)
    }
    // Prints "prop1"
    // Prints "prop2"
    
1
Harry Bloom

これらの回答は役に立ちますが、それ以上のものが必要です。私がしたいのは、プロパティのクラスタイプが既存のオブジェクトのクラスタイプと等しいかどうかを確認することだけです。オブジェクトのクラス名を取得するために、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がクラスの1つのプロパティの値になることができるかどうかを判断することはできません。それをどうやってやるの?

これが私の完全なサンプルコードです(関数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;
}
1
godspeed1024