Wie kann ich einem Objekt zur Laufzeit Eigenschaften hinzufügen?

Ist es möglich, einem Objective-C-Objekt zur Laufzeit Eigenschaften hinzuzufügen?

Es ist möglich, einer class über class_addProperty() formale Eigenschaften hinzuzufügen:

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

Die ersten beiden Parameter sind selbsterklärend. Der dritte Parameter ist ein Array von Eigenschaftsattributen, und jedes Eigenschaftsattribut ist ein Name / Wert-Paar, das Codierungen des Objective-C- Typs für deklarierte Eigenschaften folgt. Beachten Sie, dass die Dokumentation weiterhin die durch Kommas getrennte Zeichenfolge für die Codierung von Eigenschaftenattributen erwähnt. Jedes Segment in der durch Kommas getrennten Zeichenfolge wird durch eine objc_property_attribute_t Instanz dargestellt. Darüber objc_property_attribute_t akzeptiert objc_property_attribute_t classnnamen neben der generischen @ Typ-Codierung von id .

Hier ist ein erster Entwurf eines Programms, das dynamisch eine Eigenschaft namens name zu einer class hinzufügt, die bereits eine Instanzvariable namens _privateName :

 #include  #import  @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]); } } 

Seine (getrimmte) Ausgabe:

 Steve Jobs 

Die Getter- und Setter-Methoden sollten sorgfältiger geschrieben werden, aber dies sollte als Beispiel dafür ausreichen, wie eine formale Eigenschaft zur Laufzeit dynamisch hinzugefügt wird.

Wenn Sie sich das NSKeyValueCoding Protokoll NSKeyValueCoding , das hier dokumentiert ist , können Sie sehen, dass eine Nachricht namens:

 - (id)valueForUndefinedKey:(NSString *)key 

Sie sollten diese Methode überschreiben, um das benutzerdefinierte Ergebnis für die angegebene undefinierte Eigenschaft bereitzustellen. Dies setzt natürlich voraus, dass Ihre class das entsprechende Protokoll verwendet.

Diese Art von Ansatz wird üblicherweise verwendet, um classn ein unbekanntes Verhalten zu verleihen (z. B. ein Selektor, der nicht existiert).

@properties – no (dh mit Punktsyntax usw.). Sie können jedoch mithilfe von verknüpften Objekten Speicher hinzufügen: Wie verwende ich objc_setAssociatedObject / objc_getAssociatedObject in einem Objekt? .