È possibile aggiungere proprietà a un oggetto Objective C in fase di runtime?Come posso aggiungere proprietà a un oggetto in fase di runtime?
risposta
E 'possibile aggiungere proprietà formali a una classe tramite class_addProperty()
:
BOOL class_addProperty(Class cls,
const char *name,
const objc_property_attribute_t *attributes,
unsigned int attributeCount)
I primi due parametri sono auto-esplicativi. Il terzo parametro è un array di attributi di proprietà e ogni attributo di proprietà è una coppia nome-valore che segue Objective-C type encodings per declared properties. Si noti che la documentazione menziona ancora la stringa separata da virgola per la codifica degli attributi di proprietà. Ogni segmento nella stringa separata da virgola è rappresentato da un'istanza objc_property_attribute_t
. Inoltre, objc_property_attribute_t
accetta nomi di classi oltre alla codifica generica di tipo @
di id
.
Ecco una prima bozza di un programma che aggiunge dinamicamente una proprietà chiamata name
ad una classe che ha già una variabile di istanza denominata _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, "[email protected]:@");
id o = [SomeClass new];
NSLog(@"%@", [o name]);
[o setName:@"Jobs"];
NSLog(@"%@", [o name]);
}
}
sua (tagliati) Uscita:
Steve
Jobs
I metodi getter e setter dovrebbero essere scritti con più attenzione, ma questo dovrebbe essere sufficiente come esempio di come aggiungere dinamicamente una proprietà formale in fase di runtime.
class_addProperty restituisce true, ma class_getInstanceVariable restituisce sempre nil. Ho provato a mettere il nome della proprietà invece del nome di ivar, ma ancora senza fortuna. Qualche idea su quale potrebbe essere il problema? – Mercurial
@Bavarious, come hai ingannato il compilatore? Voglio dire [o nome] risultati in errore di compilazione 'Nessun metodo di istanza noto per il selettore' nome ''. –
@HiteshSavaliya molto tempo fa (prima di ARC) questo era solo possibile. al giorno d'oggi dovresti almeno dichiarare il selettore '-name'. – Michael
@proprietà - no (cioè utilizzando la sintassi del punto ecc.). Ma puoi aggiungere spazio di archiviazione usando gli oggetti associati: How do I use objc_setAssociatedObject/objc_getAssociatedObject inside an object?.
Se si dà un'occhiata a NSKeyValueCoding
protocollo, documentato here, si può vedere che c'è un messaggio chiamato:
- (id)valueForUndefinedKey:(NSString *)key
Si dovrebbe ignorare che il metodo per fornire il risultato personalizzato per la proprietà non definita specificata. Ovviamente questo presuppone che la tua classe utilizzi il protocollo corrispondente.
Questo tipo di approccio viene comunemente utilizzato per fornire un comportamento sconosciuto alle classi (ad esempio un selettore che non esiste).
se è conforme al protocollo KVC - è possibile – Nekto
Che cosa intendete esattamente per proprietà? Proprietà dichiarate Objective-C? –
Intendo @property – cfischer