¿Cómo puedo obtener una lista (en forma de NSArray
o NSDictionary
) de las propiedades de un objeto dado en Objective-C?
Imagine el siguiente escenario: he definido una clase padre que simplemente se extiende NSObject
, que contiene un NSString
, un BOOL
y un NSData
objeto como propiedades. Luego tengo varias clases que extienden esta clase principal, agregando muchas propiedades diferentes cada una.
¿Hay alguna forma de que pueda implementar un método de instancia en la clase principal que atraviese todo el objeto y devuelva, digamos, una NSArray
de cada una de las propiedades de la clase (secundaria) ya NSStrings
que no están en la clase principal, para luego poder usar estas NSString
para KVC?
[NSString stringWithCString:]
se desaprueba a favor de[NSString stringWithCString:encoding:]
.La respuesta de @ boliva es buena, pero necesita un poco más para manejar primitivas, como int, long, float, double, etc.
Me basé en el suyo para agregar esta funcionalidad.
fuente
#import <Foundation/Foundation.h>
en la parte superior del archivo .h?La respuesta de @ orange80 tiene un problema: en realidad, no siempre termina la cadena con 0. Esto puede llevar a resultados inesperados como fallar al intentar convertirlo a UTF8 (de hecho tuve un crashbug bastante molesto solo por eso. Fue divertido depurarlo ^^). Lo arreglé obteniendo un NSString del atributo y luego llamando a cStringUsingEncoding :. Esto funciona de maravilla ahora. (También funciona con ARC, al menos para mí)
Así que esta es mi versión del código ahora:
fuente
Cuando probé con iOS 3.2, la función getPropertyType no funciona bien con la descripción de la propiedad. Encontré un ejemplo de la documentación de iOS: "Objective-C Runtime Programming Guide: Declared Properties".
Aquí hay un código revisado para el listado de propiedades en iOS 3.2:
fuente
Descubrí que la solución de boliva funciona bien en el simulador, pero en el dispositivo, la subcadena de longitud fija causa problemas. He escrito una solución más amigable con Objective-C para este problema que funciona en el dispositivo. En mi versión, convierto la C-String de los atributos en una NSString y realizo operaciones de cadena en ella para obtener una subcadena de solo la descripción del tipo.
fuente
Esta implementación funciona tanto con tipos de objetos Objective-C como con primitivas C. Es compatible con iOS 8. Esta clase proporciona tres métodos de clase:
Devuelve un diccionario de todas las propiedades visibles de un objeto, incluidas las de todas sus superclases.
Devuelve un diccionario de todas las propiedades visibles de una clase, incluidas las de todas sus superclases.
Devuelve un diccionario de todas las propiedades visibles que son específicas de una subclase. No se incluyen las propiedades de sus superclases .
Un ejemplo útil del uso de estos métodos es copiar un objeto a una instancia de subclase en Objective-C sin tener que especificar las propiedades en un método de copia. . Partes de esta respuesta se basan en las otras respuestas a esta pregunta, pero proporciona una interfaz más limpia para la funcionalidad deseada.
Encabezamiento:
Implementación:
fuente
Si alguien necesita obtener también las propiedades heredadas de las clases principales (como hice yo), aquí hay alguna modificación en el código " orange80 " para hacerlo recursivo:
fuente
La palabra "atributos" es un poco confusa. ¿Te refieres a variables de instancia, propiedades, métodos que parecen accesos?
La respuesta a las tres es "sí, pero no es muy fácil". La API de tiempo de ejecución de Objective-C incluye funciones para obtener la lista de ivar, la lista de métodos o la lista de propiedades para una clase (por ejemplo,
class_copyPropertyList()
), y luego una función correspondiente para cada tipo para obtener el nombre de un elemento en la lista (por ejemplo,property_getName()
).En general, puede ser mucho trabajo hacerlo bien, o al menos mucho más de lo que la mayoría de la gente querría hacer para lo que generalmente equivale a una característica realmente trivial.
Alternativamente, puede escribir un script Ruby / Python que solo lea un archivo de encabezado y busque lo que considere "atributos" para la clase.
fuente
Pude conseguir que la respuesta de @ orange80 funcionara CON ARC ENABLED ... ... para lo que quería, al menos ... pero no sin un poco de prueba y error. Con suerte, esta información adicional puede ahorrarle a alguien el dolor.
Guarde esas clases que describe en su respuesta = como una clase, y en su
AppDelegate.h
(o lo que sea), ponga#import PropertyUtil.h
. Entonces en tu ...método (o lo que sea)
…
El secreto es lanzar la variable de instancia de su clase ( en este caso, mi clase es
Gist
, y mi instancia deGist
esgist
) que desea consultar ... a NSObject ...(id)
, etc., no lo cortará ... por varios, raro , razones esotéricas. Esto le dará un resultado como ese ...Para todos los descarados / TOC alardeando sobre la introspección "asombrosa" de ObjC ... Seguro que no hacen que sea muy fácil realizar esta simple "mirada" "a uno mismo", "por así decirlo".
Sin embargo, si realmente quieres volverte loco ... echa un vistazo a ... class-dump , que es una manera increíblemente loca de echar un vistazo a los encabezados de clase de CUALQUIER ejecutable, etc. personalmente, encuentre realmente útil, en muchas, muchas circunstancias. en realidad, es por eso que comencé a buscar una solución a la pregunta del OP. aquí están algunos de los parámetros de uso ... ¡disfrútelo!
fuente
Tienes tres hechizos mágicos
El siguiente fragmento de código puede ayudarlo.
fuente
Estaba usando la función boliva proporcionada, pero aparentemente dejó de funcionar con iOS 7. Así que ahora, en lugar de static const char * getPropertyType (propiedad objc_property_t), se puede usar lo siguiente:
fuente
Para los espectadores de Swift, puede obtener esta funcionalidad utilizando la
Encodable
funcionalidad. Explicaré como:Conforme su objeto al
Encodable
protocoloCrear extensión para
Encodable
proporcionartoDictionary
funcionalidad.Llame
toDictionary
a su instancia de objeto ykeys
propiedad de acceso .¡Voila! Accede a tus propiedades así:
fuente
Estas respuestas son útiles, pero necesito más de eso. Todo lo que quiero hacer es verificar si el tipo de clase de una propiedad es igual al de un objeto existente. Todos los códigos anteriores no son capaces de hacerlo, porque: Para obtener el nombre de clase de un objeto, object_getClassName () devuelve textos como estos:
Pero si invoca getPropertyType (...) desde el código de muestra anterior, con 4 estructuras objc_property_t de propiedades de una clase definida así:
devuelve cadenas respectivamente de la siguiente manera:
Por lo tanto, no puede determinar si un NSObject es capaz de ser el valor de una propiedad de la clase. ¿Cómo hacer eso entonces?
Aquí está mi código de muestra completo (la función getPropertyType (...) es la misma que la anterior):
fuente