2011-10-19 80 views

回答

60

有可能通过class_addProperty()正规的属性添加到一个类:

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

前两个参数是不言自明的。第三个参数是一组属性属性,每个属性属性都是一个名称 - 值对,它跟在Objective-C type encodings后面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, "[email protected]:@"); 

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

它(修剪)输出:

Steve 
Jobs 

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

+1

class_addProperty返回true,但class_getInstanceVariable总是返回nil。我已经尝试把财产名称,而不是伊娃尔名称,但仍然没有运气。任何想法可能是什么问题? – Mercurial

+1

@Bavarious,你是怎么骗人的?我的意思是[o name]导致编译错误'选择器'name'没有已知的实例方法'。 –

+0

@HiteshSavaliya很久以前(ARC之前),这是可能的。现在你至少必须声明'-name'选择器。 – Michael

8

如果你看一看NSKeyValueCoding协议,记录here,你可以看到,有一个名为消息:

- (id)valueForUndefinedKey:(NSString *)key 

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

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

相关问题