运行时的 Objective-C 动态属性?

标签 objective-c

是否可以创建一个在运行时可以具有任意数量的动态属性的 Objective-C 类?

我希望能够调用 mySpecialClass.anyProperty 并在我的类中拦截它,以便能够提供我自己的自定义实现,然后返回一个 NSString(对于实例)在运行时引发异常。显然这一切都必须编译。

理想情况下,如果我可以使用类似于新文字语法的东西来引用我的属性,例如mySpecialClass["anyProperty"]

我想在某种程度上我想创建一个没有 CFDictionary 后备存储的动态 NSDictionary 之类的东西,它分别在属性获取和设置上执行 2 个自定义方法,并将属性名称传递给这些访问器方法,以便他们可以决定什么做。

最佳答案

至少有两种方法可以做到这一点。

订阅

使用objectForKeyedSubscript:setObject:forKeyedSubscript:

 @property (nonatomic,strong) NSMutableDictionary *properties;

 - (id)objectForKeyedSubscript:(id)key {
      return [[self properties] valueForKey:[NSString stringWithFormat:@"%@",key]];
 }

 - (void)setObject:(id)object forKeyedSubscript:(id <NSCopying>)key {
      [[self properties] setValue:object forKey:[NSString stringWithFormat:@"%@",key]];
 }

 Person *p = [Person new];
 p[@"name"] = @"Jon";
 NSLog(@"%@",p[@"name"]);

解析实例方法:

这是运行时为所有方法执行的objc_sendMsg:

objc_sendMsg

如果您查看底部,您将有机会 resolveInstanceMethod:,它可以让您将方法调用重定向到您选择的方法之一。要回答您的问题,您需要编写一个通用的 getter 和 setter 来查找字典 ivar 上的值:

// generic getter
static id propertyIMP(id self, SEL _cmd) {
    return [[self properties] valueForKey:NSStringFromSelector(_cmd)];
}


// generic setter
static void setPropertyIMP(id self, SEL _cmd, id aValue) {

    id value = [aValue copy];
    NSMutableString *key = [NSStringFromSelector(_cmd) mutableCopy];

    // delete "set" and ":" and lowercase first letter
    [key deleteCharactersInRange:NSMakeRange(0, 3)];
    [key deleteCharactersInRange:NSMakeRange([key length] - 1, 1)];
    NSString *firstChar = [key substringToIndex:1];
    [key replaceCharactersInRange:NSMakeRange(0, 1) withString:[firstChar lowercaseString]];

    [[self properties] setValue:value forKey:key];
}

然后实现resolveInstanceMethod:将请求的方法添加到类中。

+ (BOOL)resolveInstanceMethod:(SEL)aSEL {
    if ([NSStringFromSelector(aSEL) hasPrefix:@"set"]) {
        class_addMethod([self class], aSEL, (IMP)setPropertyIMP, "v@:@");
    } else {
        class_addMethod([self class], aSEL,(IMP)propertyIMP, "@@:");
    }
    return YES;
}

您也可以为该方法返回 NSMethodSignature,然后将其包装在 NSInvocation 中并传递给 forwardInvocation:,但添加该方法会更快。

Here is a gist在 CodeRunner 中运行。它不处理 myClass["anyProperty"] 调用。

关于运行时的 Objective-C 动态属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13645666/

相关文章:

objective-c - 如何确定 OS X 10.10 之前的应用程序 session 之间的文件等效性?

iphone - Xcode 4.2 首选项 "Support Wirelessly Connected Devices"有什么作用?

iphone - 异步添加图像 - ASIHTTPRequest

objective-c - NSNumber 与 NSInteger 与 NSObject 属性的 int

objective-c - awakeFromNib 之后 NSWindow 为零

objective-c - 将时间转换为 float

iphone - 如何在此方法中实现删除/撤消

objective-c - Objective-C 中的二叉树

objective-c - 游戏中心 : authenticates ok, 显示排行榜正常,帖子(我的)得分正常,只有 2 个玩家?

ios - 无法删除 uicollectionviewcell 底部的间距?