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

时间:2011-10-19 09:20:40

标签: objective-c cocoa properties objective-c-runtime

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

3 个答案:

答案 0 :(得分:60)

可以通过class_addProperty()

向类中添加正式属性
BOOL class_addProperty(Class cls,
    const char *name,
    const objc_property_attribute_t *attributes,
    unsigned int attributeCount)

前两个参数是不言自明的。第三个参数是属性属性数组,每个属性属性都是一个名称 - 值对,它遵循type encodings的Objective-C declared properties。请注意,文档仍然提到了用于编码属性属性的逗号分隔字符串。逗号分隔字符串中的每个段由一个objc_property_attribute_t实例表示。此外,objc_property_attribute_t@的通用id类型编码外,还接受类名。

这是一个程序的初稿,它动态地将一个名为name的属性添加到已经有一个名为_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, "v@:@");

        id o = [SomeClass new];
        NSLog(@"%@", [o name]);
        [o setName:@"Jobs"];
        NSLog(@"%@", [o name]);
    }
}

其(修剪)输出:

Steve
Jobs

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

答案 1 :(得分:8)

如果您查看NSKeyValueCoding协议(记录为here),您会发现有一条消息称为:

- (id)valueForUndefinedKey:(NSString *)key

您应该覆盖该方法,以便为指定的undefined属性提供自定义结果。当然,这假设您的班级使用相应的协议。

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

答案 2 :(得分:4)

@properties - no(即使用点语法等)。但您可以使用关联对象添加存储:How do I use objc_setAssociatedObject/objc_getAssociatedObject inside an object?