получить список свойств объекта в objective-c

<p>как я могу получить список (в виде <code>nsarray</code> или <code>nsdictionary</code>) заданных свойств объекта в objective-c?</p><p>представьте себе следующий сценарий: я определил родительский класс, который просто расширяет <code>nsobject</code>, который содержит <code>nsstring</code>, <code>bool</code> и <code>nsdata</code> в качестве свойств. затем у меня есть несколько классов, которые расширяют этот родительский класс, добавляя множество различных свойств каждый.</p><p>можно ли как-нибудь реализовать метод экземпляра в классе <em>parent</em>, который проходит через весь объект и возвращает, скажем, <code>nsarray</code> каждого из свойств (дочернего) класса как <code>nsstrings</code>, которые <em>не</em> в родительском классе, так что я могу позже использовать эти <code>nsstring</code> для kvc?</p>

<p>мне просто удалось получить ответ сам. используя библиотеку времени выполнения obj-c, я получил доступ к свойствам так, как хотел:</p><pre><code>- (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); } </code></pre><p>это потребовало от меня создания c-функции 'getpropertytype', которая в основном взята из примера кода apple (прямо сейчас не могу вспомнить точный источник):</p><pre><code>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 "@"; } </code></pre>

<p>ответ @ boliva хорош, но для обработки примитивов, таких как int, long, float, double и т. д., требуется немного больше.</p><p>я построил его, чтобы добавить эту функциональность.</p><pre><code>// 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 </code></pre>

<p>ответ @ orange80 имеет одну проблему: фактически он не всегда завершает строку 0. это может привести к неожиданным результатам, таким как сбой при попытке конвертировать его в utf8 (из-за этого у меня был довольно надоедливый краш-баг. было весело отлаживать его ^^). я исправил это, фактически получив nsstring из атрибута и затем вызвав cstringusingencoding :. это работает как шарм сейчас. (также работает с arc, по крайней мере, для меня)</p><p>так что теперь это моя версия кода:</p><pre><code>// 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 </code></pre>

<p>когда я пытался с ios 3.2, функция getpropertytype не очень хорошо работает с описанием свойства. я нашел пример из документации ios: "руководство по программированию во время выполнения objective c: объявленные свойства".</p><p>вот пересмотренный код для перечисления свойств в ios 3.2:</p><pre><code>#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); </code></pre>

<p>я обнаружил, что решение boliva отлично работает в симуляторе, но на устройстве подстрока фиксированной длины вызывает проблемы. я написал более подходящее для objective-c решение этой проблемы, которое работает на устройстве. в моей версии я преобразую c-строку атрибутов в строку nsstring и выполняю над ней строковые операции, чтобы получить подстроку только описания типа.</p><pre><code>/* * @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; } </code></pre>

<p>эта реализация работает как с объектными типами objective-c, так и с примитивами c. это совместимо с ios 8. этот класс предоставляет три метода класса:</p><pre><code>+ (nsdictionary *) propertiesofobject:(id)object; </code></pre><p>возвращает словарь всех видимых свойств объекта, включая свойства всех его суперклассов.</p><pre><code>+ (nsdictionary *) propertiesofclass:(class)class; </code></pre><p>возвращает словарь всех видимых свойств класса, включая свойства всех его суперклассов.</p><pre><code>+ (nsdictionary *) propertiesofsubclass:(class)class; </code></pre><p>возвращает словарь всех видимых свойств, которые <em> специфичны </em> для подкласса. свойства его суперклассов <em> не включены </em>.</p><p>одним из полезных примеров использования этих методов является <a href="https://stackoverflow.com/questions/27336371/transform-or-copy-an-object-to-a-subclass-instance-in-objective-c">скопировать объект в экземпляр подкласса в objective-c без необходимости указывать свойства в методе копирования</a> . части этого ответа основаны на других ответах на этот вопрос, но он обеспечивает более чистый интерфейс для желаемой функциональности.</p><p>заголовок:</p><pre><code>// synutilities.h #import <foundation/foundation.h> @interface synutilities : nsobject + (nsdictionary *) propertiesofobject:(id)object; + (nsdictionary *) propertiesofclass:(class)class; + (nsdictionary *) propertiesofsubclass:(class)class; @end </code></pre><p>реализация:</p><pre><code>// 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 </code></pre>

<p>если кто-то также нуждается в получении <strong> свойств, унаследованных от родительских классов </strong> (как я сделал), здесь есть некоторая модификация на "<strong> <a href="https://stackoverflow.com/questions/754824/get-an-object-attributes-list-in-objective-c/8380836#8380836">orange8</a> </strong> "код, чтобы сделать его рекурсивным:</p><pre><code>+ (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]; } } </code></pre>

<p>слово "атрибуты" немного нечетко. вы имеете в виду переменные экземпляра, свойства, методы, которые выглядят как методы доступа?</p><p>ответ на все три вопроса - "да, но это не очень легко". <a href="http://developer.apple.com/documentation/cocoa/reference/objcruntimeref/reference/reference.html">objective-c runtime api</a> включает функции для получения списка ivar, списка методов или списка свойств для класса (например, <code>class\_copypropertylist()</code>), а затем соответствующую функцию для каждого типа, чтобы получить имя элемента в списке (например, <code>property\_getname()</code>).</p><p>в целом, чтобы сделать это правильно, может потребоваться много работы, или, по крайней мере, гораздо больше, чем хотелось бы большинству людей, что обычно составляет действительно тривиальную функцию.</p><p>в качестве альтернативы, вы можете просто написать скрипт на ruby/python, который просто читает заголовочный файл и ищет все, что вы считаете "атрибутами" для класса.</p>

<p>я смог получить ответ @ orange80 для работы <strong> с включенной дугой </strong> ... ... для того, что я хотел - по крайней мере ... но не без долга проб и ошибок. надеюсь, эта дополнительная информация может избавить кого-то от горя.</p><p>сохраните <a href="https://stackoverflow.com/a/8380836/547214">те классы, которые он описывает в своем ответе</a> = как класс, и в свой <code>appdelegate.h</code> (или любой другой) поместите <code>#import propertyutil.h</code>. тогда в вашем ...</p><pre><code>- (void)applicationdidfinishlaunching: (nsnotification *)anotification { </code></pre><p>метод (или любой другой) <code>…</code></p><pre><code>propertyutil *props = [propertyutil new]; nsdictionary *propsd = [propertyutil classpropsfor: (nsobject*)[gist class]]; nslog(@"%@, %@", props, propsd); … </code></pre><p>секрет в том, чтобы привести переменную экземпляра вашего класса (<em> в этом случае мой класс - <code>gist</code>, а мой экземпляр <code>gist</code> - <code>gist</code> </em>), который вы хотите запросить ... <strong> объекту nsobject </strong>… <code>(id)</code> и т. д. не будет сокращать его… по различным, странным, эзотерическим причинам. это даст вам некоторый результат, как так ...</p><pre><code><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; } </code></pre><p>несмотря на то, что apple беззастенчиво/ocd хвастается интроспекцией objc "amazeballs" ... они, конечно, не позволяют легко выполнить этот простой "взгляд" "на себя", "так сказать" ..</p><p>если вы действительно хотите свихнуться, хотя ... проверьте ... <strong> <a href="http://www.codethecode.com/projects/class-dump/">class-dump</a> , что является ошеломляющим безумным способом заглянуть в заголовки классов </strong> любого исполняемого файла и т. д. ... он дает главный взгляд на ваши уроки ..., который я лично считаю действительно полезным - во многих, многих обстоятельствах. именно поэтому я начал искать решение вопроса оп. вот некоторые параметры использования .. наслаждайтесь!</p><pre><code> -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 </code></pre>

<p>у вас есть три магических заклинания</p><pre><code>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. </code></pre><p>следующий фрагмент кода может помочь вам.</p><pre><code>-(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); } </code></pre>

<p>я использовал функцию boliva, но, по-видимому, она перестала работать с ios 7. так что теперь вместо статического const char * getpropertytype (свойство objc\_property\_t) можно просто использовать следующее:</p><pre><code>- (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:@""]; } </code></pre>

<p>для наблюдателей swift вы можете получить эту функцию, используя функцию <code>encodable</code>. я объясню, как:</p><ol> <li> <p>согласуйте ваш объект с протоколом <code>encodable</code></p> <pre><code>class exampleobj: nsobject, encodable { var prop1: string = "" var prop2: string = "" } </code></pre></li> <li> <p>создайте расширение для <code>encodable</code>, чтобы обеспечить функциональность <code>todictionary</code></p> <pre><code> 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 } </code></pre></li> <li> <p>вызовите <code>todictionary</code> для своего экземпляра объекта и получите доступ к свойству <code>keys</code>.</p> <pre><code>let exampleobj = exampleobj() exampleobj.todictionary()?.keys </code></pre></li> <li> <p>вуаля! получите доступ к вашей недвижимости следующим образом:</p> <pre><code>for k in exampleobj!.keys { print(k) } // prints "prop1" // prints "prop2" </code></pre></li> </ol>

<p>эти ответы полезны, но мне нужно больше от этого. все, что я хочу сделать, это проверить, равен ли тип класса свойства существующему объекту. все приведенные выше коды не способны сделать это, потому что: чтобы получить имя класса объекта, object\_getclassname () возвращает тексты, подобные этим:</p><pre><code>\_\_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:]) </code></pre><p>но если вызывать getpropertytype (...) из приведенного выше примера кода, то wit 4 objc\_property\_t структурирует свойства класса, определенного следующим образом:</p><pre><code>@property (nonatomic, strong) nsarray* a0; @property (nonatomic, strong) nsarray* a1; @property (nonatomic, copy) nsnumber* n0; @property (nonatomic, copy) nsvalue* n1; </code></pre><p>он возвращает строки соответственно следующим образом:</p><pre><code>nsarray nsarray nsnumber nsvalue </code></pre><p>таким образом, он не может определить, способен ли nsobject быть значением одного свойства класса. как это сделать тогда?</p><p>вот мой полный пример кода (функция getpropertytype (...) такая же, как и выше):</p><pre><code>#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; } </code></pre>