【问题标题】:Can I modify a variable via it's name as a string? [duplicate]我可以通过变量名作为字符串修改变量吗? [复制]
【发布时间】:2013-05-18 18:34:38
【问题描述】:

我有什么方法可以从包含变量名的字符串中修改变量吗?

类似这样的:

int example = 1;
NSString *foo = @"example";
foo.value++

此时,example 将等于 2。

【问题讨论】:

标签: objective-c


【解决方案1】:

你不能用这样的局部变量来做到这一点。您可以使用KVC 来处理实例变量。

【讨论】:

  • 如果你真的想的话,你实际上可以用本地人来做这件事,但有人会认为这涉及服务器运行时和宏黑客。没有不可能,只有不切实际。
【解决方案2】:

与其他答案相反,如果您愿意完全破解模式,这确实是可能的。使用 C 中的宏和指针的力量,我完成了这项任务(它还包括有关对象类型的信息,以防您需要知道在运行时要做什么)。

用这个作为一个有趣的例子,但要小心 - 它会增加相当多的内存使用量。

首先,让我们展示您将如何使用这些 API:


ma​​in.m:

#import <Foundation/Foundation.h>
#import "IndexedVariable.h"

int main() {
    INDEXED_VAR(int, example, 1);

    NSString *foo = @"example";

    GET_INDEXED_VAR_AS(foo, int)++;

    NSLog(@"%i", example);
}

IndexedVariable.h:

#import <Foundation/Foundation.h>

// feel free to not use these macros, but I feel they make it much easier to read
#define choose_if __builtin_choose_expr
#define compatible __builtin_types_compatible_p

#define INDEXED_TYPE_FROM_NAME(p_type) \
    choose_if(compatible(signed char   , p_type), INDEXED_TYPE_SIGNED_CHAR,\
    choose_if(compatible(unsigned char , p_type), INDEXED_TYPE_UNSIGNED_CHAR,\
    choose_if(compatible(signed short  , p_type), INDEXED_TYPE_SIGNED_SHORT,\
    choose_if(compatible(unsigned short, p_type), INDEXED_TYPE_UNSIGNED_SHORT,\
    choose_if(compatible(signed int    , p_type), INDEXED_TYPE_SIGNED_INT,\
    choose_if(compatible(unsigned int  , p_type), INDEXED_TYPE_UNSIGNED_INT,\
    choose_if(compatible(signed long   , p_type), INDEXED_TYPE_SIGNED_LONG,\
    choose_if(compatible(unsigned long , p_type), INDEXED_TYPE_UNSIGNED_LONG,\
    choose_if(compatible(float         , p_type), INDEXED_TYPE_FLOAT,\
    choose_if(compatible(double        , p_type), INDEXED_TYPE_DOUBLE,\
    choose_if(compatible(id            , p_type), INDEXED_TYPE_OBJC_OBJECT,\
    choose_if(compatible(void *        , p_type), INDEXED_TYPE_GENERIC_POINTER,\
    INDEXED_TYPE_UNKNOWN\
))))))))))))

#define INDEXED_VAR(p_type, p_name, p_initial_value)\
p_type p_name = p_initial_value;\
IndexedVariable *__indexed_ ## p_name = [IndexedVariable index:INDEXED_TYPE_FROM_NAME(p_type) :@#p_name :&p_name];\
(void) __indexed_ ## p_name

#define GET_INDEXED_VAR_AS(p_name, type)  (*((type *) [[IndexedVariable lookupWithName:p_name] address]))

// represents the type of an indexed variable
enum INDEXED_TYPE {
    INDEXED_TYPE_SIGNED_CHAR,
    INDEXED_TYPE_UNSIGNED_CHAR,
    INDEXED_TYPE_SIGNED_SHORT,
    INDEXED_TYPE_UNSIGNED_SHORT,
    INDEXED_TYPE_SIGNED_INT,
    INDEXED_TYPE_UNSIGNED_INT,
    INDEXED_TYPE_SIGNED_LONG,
    INDEXED_TYPE_UNSIGNED_LONG,

    INDEXED_TYPE_FLOAT,
    INDEXED_TYPE_DOUBLE,

    INDEXED_TYPE_OBJC_OBJECT,
    INDEXED_TYPE_GENERIC_POINTER,

    INDEXED_TYPE_UNKNOWN,
};

@interface IndexedVariable : NSObject 

+(id) index:(enum INDEXED_TYPE) indexedType :(NSString *) varName :(void *) ptr;
+(IndexedVariable *) lookupWithName:(NSString *) name;

-(enum INDEXED_TYPE) indexedType;
-(void *) address;

@end

IndexedVariable.m:

#import "IndexedVariable.h"

static NSMutableDictionary *indexedVariableDictionary;

@implementation IndexedVariable {
    enum INDEXED_TYPE _type;
    void *_address;
}

+(id) index:(enum INDEXED_TYPE)indexedType :(NSString *)varName :(void *)ptr
{
    IndexedVariable *var = [IndexedVariable new];

    var->_type = indexedType;
    var->_address = ptr;

    if (indexedVariableDictionary == nil) {
        indexedVariableDictionary = [NSMutableDictionary new];
    }

    indexedVariableDictionary[varName] = [NSValue valueWithNonretainedObject:var];

    return var;
}

+(IndexedVariable *) lookupWithName:(NSString *)name
{
    return [indexedVariableDictionary[name] nonretainedObjectValue];
}

-(enum INDEXED_TYPE) indexedType {
    return _type;
}

-(void *) address {
    return _address;
}

-(void) dealloc {
    NSArray *keys = [indexedVariableDictionary allKeysForObject:[NSValue valueWithNonretainedObject:self]];
    [indexedVariableDictionary removeObjectsForKeys:keys];
}

@end

您可以在此示例中查找索引变量,其他任何内容都不会出现在查找表中。

【讨论】:

  • 令人惊讶的是,这可以简化为在使用 NSDictionaryOfVariableBindings() 宏 Apple 为我们提供的 AutoLayout 制作的字典中查找;)
  • @CodaFi 不幸的是,它不适用于值类型,就像我的那样。
【解决方案3】:

我不知道任何可以让你这样做的语言。

在这种特殊情况下,您可以将指针传递给int

更一般地说,如果您想通过名称来操作某些东西,请使用字典:

NSDictionary* d = @{@"example":@1};
NSString* key = @"example";
d[key] = @([d[key] intValue] + 1);

【讨论】:

  • 如果你愿意,Python 提供了这种绳索(就像其他解释语言可能做的那样):&gt;&gt;&gt; a = 10 &gt;&gt;&gt; locals()['a'] = 12 &gt;&gt;&gt; a12
  • 和javascript一样,您可以使用eval,以及其他几种更复杂的方式。
  • 哦,是的,eval - 忘了那种事!
  • 早在 1980 年代,许多 BASIC 就做到了这一点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-10-13
  • 2012-07-18
  • 1970-01-01
  • 1970-01-01
  • 2019-02-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多