运行时的Objective-C动态属性? [英] Objective-C dynamic properties at runtime?

查看:106
本文介绍了运行时的Objective-C动态属性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Is it possible to create an Objective-C class that can have an arbitrary number of dynamic properties at runtime?

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

I want to be able to call mySpecialClass.anyProperty and intercept this inside my class to be able to provide my own custom implementation that can then return an NSString (for instance) at runtime with raising an exception. Obviously this all has to compile.

理想的情况是,我可以使用类似于新的文字语法的方式来引用我的属性,例如mySpecialClass["anyProperty"].

Ideal would be if I could refer to my properties using something similar to the new literal syntax, e.g. mySpecialClass["anyProperty"].

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

I guess in a way I want to create something like a dynamic NSDictionary with no CFDictionary backing store, that executes 2 custom methods on property getting and setting respectively, with the property name passed in to these accessor methods so they can decide what to do.

推荐答案

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

There are at least two ways to do this.

使用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"]);

resolveInstanceMethod:

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

resolveInstanceMethod:

This is the objc_sendMsg executed by the runtime for all methods:

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

If you look at the bottom, you have the opportunity to resolveInstanceMethod:, which lets you redirect the method call to one of your choosing. To answer your question, you need to write a generic getter and setter that looks-up a value on a dictionary 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:将请求的方法添加到类中.

And then implement resolveInstanceMethod: to add the requested method to the class.

+ (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:,但是添加该方法的速度更快.

You could also do it returning a NSMethodSignature for the method, which is then wrapped in a NSInvocation and passed to forwardInvocation:, but adding the method is faster.

这是在CodeRunner中运行的要点.它不处理myClass["anyProperty"]呼叫.

这篇关于运行时的Objective-C动态属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆