2011-10-19 16 views

Odpowiedz

60

Jest możliwe, aby dodać właściwości formalnych do klasy poprzez class_addProperty():

BOOL class_addProperty(Class cls, 
    const char *name, 
    const objc_property_attribute_t *attributes, 
    unsigned int attributeCount) 

Pierwsze dwa parametry są oczywiste. Trzeci parametr jest tablicą atrybutów właściwości, a każdy atrybut właściwości jest parą nazwa-wartość, która jest zgodna z Objective-C type encodings dla declared properties. Zauważ, że dokumentacja wciąż wspomina o ciągu oddzielonym przecinkami dla kodowania atrybutów właściwości. Każdy segment w łańcuchu oddzielonym przecinkiem jest reprezentowany przez jedną instancję objc_property_attribute_t. Ponadto, objc_property_attribute_t akceptuje nazwy klas oprócz ogólnego kodowania typu @ z id.

Oto pierwszy projekt programu, który dynamicznie dodaje właściwość o nazwie name do klasy, która ma już zmienną instancji o nazwie _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]); 
    } 
} 

Jego (przycinane) Wyjście:

Steve 
Jobs 

Metody getter i setter powinny być pisane ostrożniej, ale powinno to wystarczyć jako przykład dynamicznego dodawania formalnej właściwości w czasie wykonywania.

+1

class_addProperty zwraca true, ale class_getInstanceVariable zawsze zwraca zero. Próbowałem wstawić nazwę właściwości zamiast nazwy ivar, ale wciąż nie miałem szczęścia. Jakiś pomysł, jaki może być problem? – Mercurial

+1

@Barious, jak udało ci się wygłupiać? Mam na myśli, że [o name] powoduje błąd kompilacji "Brak znanej metody dla nazwy selektora". –

+0

@HiteshSavaliya dawno temu (przed ARC) było to po prostu możliwe. w dzisiejszych czasach musielibyśmy przynajmniej zadeklarować selektor '-name'. – Michael

8

Jeśli spojrzeć na protokole NSKeyValueCoding, udokumentowany here, można zobaczyć, że nie jest to wiadomość o nazwie:

- (id)valueForUndefinedKey:(NSString *)key 

Należy zastąpić tę metodę w celu zapewnienia niestandardowej wynik dla określonego niezdefiniowanej właściwości. Oczywiście zakłada to, że twoja klasa używa odpowiedniego protokołu.

Tego rodzaju podejście jest powszechnie stosowane w celu zapewnienia nieznanego zachowania dla klas (np. Selektora, który nie istnieje).

Powiązane problemy