如何在运行时将属性添加到对象?

是否有可能在运行时向Objective C对象添加属性?

可以通过class_addProperty()将正式属性添加到类中:

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

前两个参数是不言自明的。 第三个参数是属性属性数组,每个属性属性都是一个名称 – 值对,对于已声明的属性 ,它是Objective-C types的编码 。 请注意该文档仍然提到了属性属性编码的逗号分隔的string。 逗号分隔的string中的每个段由一个objc_property_attribute_t实例表示。 此外, objc_property_attribute_t接受除了id的通用@types编码之外的类名称。

下面是一个程序的初稿,它dynamic地将一个名为name的属性添加到已经有一个名为_privateName的实例variables的类中:

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

其(修剪)输出:

 Steve Jobs 

getter和setter方法应该更仔细地编写,但是这应该足以作为如何在运行时dynamic添加正式属性的示例。

如果你看看这里logging的NSKeyValueCoding协议,你可以看到有一条消息叫做:

 - (id)valueForUndefinedKey:(NSString *)key 

您应该重写该方法来为指定的未定义属性提供自定义结果。 当然这假设你的class级使用相应的协议。

这种方法通常用于向类提供未知的行为(例如,不存在的select器)。

@properties – 否(即使用点语法等)。 但是您可以使用关联的对象添加存储: 如何在对象内部使用objc_setAssociatedObject / objc_getAssociatedObject? 。