objective-c - tiempo - parametros dinamicos c#
¿Cómo puedo agregar propiedades a un objeto en tiempo de ejecución? (3)
¿Es posible agregar propiedades a un objeto Objective C en tiempo de ejecución?
@properties - no (es decir, usando sintaxis de punto, etc.). Pero puede agregar almacenamiento usando objetos asociados: ¿Cómo uso objc_setAssociatedObject / objc_getAssociatedObject dentro de un objeto? .
Si NSKeyValueCoding
un vistazo al protocolo NSKeyValueCoding
, documentado here , puedes ver que hay un mensaje llamado:
- (id)valueForUndefinedKey:(NSString *)key
Debe anular ese método para proporcionar su resultado personalizado para la propiedad indefinida especificada. Por supuesto, esto supone que su clase utiliza el protocolo correspondiente.
Este tipo de enfoque se usa comúnmente para proporcionar un comportamiento desconocido a las clases (por ejemplo, un selector que no existe).
Es posible agregar propiedades formales a una clase a través de class_addProperty()
:
BOOL class_addProperty(Class cls,
const char *name,
const objc_property_attribute_t *attributes,
unsigned int attributeCount)
Los primeros dos parámetros son autoexplicativos. El tercer parámetro es una matriz de atributos de propiedad, y cada atributo de propiedad es un par nombre-valor que sigue codificaciones de tipo Objective-C para las propiedades declaradas . Tenga en cuenta que la documentación aún menciona la cadena separada por comas para la codificación de los atributos de propiedad. Cada segmento en la cadena separada por comas está representado por una instancia objc_property_attribute_t
. Además, objc_property_attribute_t
acepta nombres de clase además de la codificación genérica @
type de id
.
Aquí hay un primer borrador de un programa que agrega dinámicamente una propiedad llamada name
a una clase que ya tiene una variable de instancia llamada _privateName
:
#include <objc/runtime.h>
#import <Foundation/Foundation.h>
@interface SomeClass : NSObject {
NSString *_privateName;
}
@end
@implementation SomeClass
- (id)init {
self = [super init];
if (self) _privateName = @"Steve";
return self;
}
@end
NSString *nameGetter(id self, SEL _cmd) {
Ivar ivar = class_getInstanceVariable([SomeClass class], "_privateName");
return object_getIvar(self, ivar);
}
void nameSetter(id self, SEL _cmd, NSString *newName) {
Ivar ivar = class_getInstanceVariable([SomeClass class], "_privateName");
id oldName = object_getIvar(self, ivar);
if (oldName != newName) object_setIvar(self, ivar, [newName copy]);
}
int main(void) {
@autoreleasepool {
objc_property_attribute_t type = { "T", "@/"NSString/"" };
objc_property_attribute_t ownership = { "C", "" }; // C = copy
objc_property_attribute_t backingivar = { "V", "_privateName" };
objc_property_attribute_t attrs[] = { type, ownership, backingivar };
class_addProperty([SomeClass class], "name", attrs, 3);
class_addMethod([SomeClass class], @selector(name), (IMP)nameGetter, "@@:");
class_addMethod([SomeClass class], @selector(setName:), (IMP)nameSetter, "v@:@");
id o = [SomeClass new];
NSLog(@"%@", [o name]);
[o setName:@"Jobs"];
NSLog(@"%@", [o name]);
}
}
Su salida (recortada):
Steve
Jobs
Los métodos getter y setter deberían escribirse con más cuidado, pero esto debería ser suficiente como un ejemplo de cómo agregar dinámicamente una propiedad formal en tiempo de ejecución.