2011-10-19 16 views

risposta

60

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.

+1

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

+1

@Bavarious, come hai ingannato il compilatore? Voglio dire [o nome] risultati in errore di compilazione 'Nessun metodo di istanza noto per il selettore' nome ''. –

+0

@HiteshSavaliya molto tempo fa (prima di ARC) questo era solo possibile. al giorno d'oggi dovresti almeno dichiarare il selettore '-name'. – Michael

8

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).

Problemi correlati