可以在运行时向目标C对象添加属性吗?

推荐答案

可以通过class_addProperty()向类添加形式属性:

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

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

下面是一个程序的初稿,它动态地将一个名为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方法,但这应该足以作为如何在运行时动态添加形式属性的示例.

Objective-c相关问答推荐

UITableViewCell:如何防止蓝色 Select ​​背景不带 isSelected 属性?

Objective-C 中的实例变量是否默认设置为 nil?

iPhone SDK 网络连接检测

tableView:canEditRowAtIndexPath: 弹出 viewController 时崩溃

pathForResource 返回 null

为什么我不用 * 声明 NSInteger

如何创建 NSIndexPath:indexPathWithIndexes:length 所需的索引:

在 Objective-C 类中混合 C 函数

使用自动布局以编程方式更改框架

setStatusBarHidden 在 iOS 9.0 中已弃用

Objective-C (cocoa) 等价于python的endswith/beginswith

在运行时判断 iOS 版本?

iOS 内存分配 - 一个应用程序可以使用多少内存?

在 iPhone 应用程序中使用 RestKit 的最佳方式

添加自定义 initWith?

在不导入自己的情况下播放系统声音

如何在 ios 8 的 alertview 中添加文本输入?

在 Objective-C 中_和touch之间的区别

字符串常量和字符串文字有什么区别?

如何定义 UIColor 的常量值?