2009-04-16 2 views
101

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

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

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

ответ

106

Мне просто удалось получить ответ сам. С помощью Obj-C Runtime библиотеки, я имел доступ к свойствам, как я хотел:

- (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 "@"; 
} 
+4

+1 кроме этого будет ошибка на примитивах, таких как int. Пожалуйста, см. Мой ответ ниже для слегка расширенной версии этой же вещи. – jpswain

+1

Кажется, что не работает с ARC? – Ford

+1

Он работает с ARC. –

3

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

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

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

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

+0

Привет, патрон, спасибо за ваш ответ. То, что я называю «атрибутами», действительно было для свойств класса. Мне уже удалось выполнить то, что я хотел, используя библиотеку времени Obj-C. Использование сценария для анализа файла заголовка не сработало бы для того, что мне нужно во время выполнения. – boliva

8

Когда я попытался с прошивкой 3.2, функция getPropertyType не очень хорошо работает с описанием свойств. Я нашел пример из документации iOS: «Руководство по программированию Runtime Objective-C: объявленные свойства».

Вот пересмотренный код недвижимости листинга в прошивкой 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); 
69

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

Я построил его, чтобы добавить эту функциональность.

// 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 

+0

Это фантастический код! благодаря! – dreampowder

+0

Отлично работает. Благодаря! – kevinejohn

+1

Вы намеревались иметь '#import ' в верхней части файла .h? – Andrew

4

Я был в состоянии получить @ ответ orange80 на работу АРК ВКЛЮЧЕНО ... ... за то, что я хотел - по крайней мере ... но не без толики проб и ошибок. Надеюсь, эта дополнительная информация может сэкономить кому-то горе.

Сохраните 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 is 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 бахвальства о «amazeballs» ObjC в «самоанализе ... Они, конечно, не делают его очень легко выполнить этот простой„взгляд“ «в самом себе», «так сказать» ..

Если вы действительно хотите пойти боры дикими, хотя .. проверить .. 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 
7

Я нашел, что решение boliva отлично работает в симуляторе, но на устройстве подстрока с фиксированной длиной вызывает проблемы. Я написал более объективное решение для этой проблемы, которое работает на устройстве. В моей версии я преобразую 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; 
} 
+0

Это исключение EXC_BAD_ACCESS в NSRange const typeRangeStart = [attributes rangeOfString: @ "T @ \" "]; // начало строки типа –

28

@ Ответ на оранжевый80 имеет одну проблему: он на самом деле не всегда завершает строку с 0s. Это может привести к неожиданным результатам, например, сбой при попытке конвертировать его в UTF8 (у меня на самом деле был довольно раздражающий crashbug именно из-за этого. Было весело отлаживать его ^^). Я исправил это, фактически получив NSString из атрибута, а затем вызвав cStringUsingEncoding :. Сейчас это работает как шарм. (Также работает с АРК, по крайней мере, для меня)

Так что это моя версия кода в настоящее время:

// 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 
+0

Это решение отлично работает с ios 7. – Ramiro

+0

@farthen вы можете привести пример, демонстрирующий проблему с кодом, который я предоставил? Мне просто любопытно это увидеть. – jpswain

+0

@ orange80 Ну, AFAIR данные никогда не заканчиваются нулем. Если это происходит только при аварии. Возможно, я ошибаюсь. В других новостях: у меня все еще есть этот код, и он работает с твердой вещью: p – Farthen

2

Я использовал функцию Boliva при условии, но, видимо, он перестал работать с прошивкой 7. Так что теперь вместо статического Const символ * 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:@""]; 
} 
+0

Ты мой герой. Мне все же приходится вручную исправлять некоторые вещи (по какой-то причине BOOLs появляются как «Tc»), но это фактически позволило мне снова начать работать. – Harpastum

+0

Примитивы имеют свой собственный тип, «@» обозначает объекты, а после него появляется имя класса между кавычками. Единственным исключением является id, который кодируется просто как «T @» –

4

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

    } 
} 
+1

Не удалось ли сделать эту категорию и расширить NSObject, чтобы эта функциональность была встроена в каждый класс, являющийся дочерним элементом NSObject? –

+0

Это звучит неплохо, если я смогу найти, время обновит ответ с помощью этой опции. – Emilio

+0

Как только вы закончите с этим, я добавлю дамп метода, когда у меня будет время. Пришло время, когда мы получили реальное свойство объекта и интроспекцию метода поверх каждого NSObject. –

5

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

Я получаю исключение EXC_BAD_ACCESS в этой строке NSString * name = [[NSString alloc] initWithBytes: attribute + 1 length: strlen (атрибут) - 1 кодировка: NSASCIIStringEncoding]; –

1

Эти ответы являются полезными, но требуют большего от этого. Все, что я хочу сделать, это проверить, соответствует ли тип класса свойства объекту существующего объекта. Все вышеуказанные коды не в состоянии сделать это, потому что: Чтобы получить имя класса объекта, 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 

так что я s не может определить, способен ли 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; 
} 
2

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

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); 
} 
Смежные вопросы