2

Is there any way for me to modify a variable from a string containing it's name?

Something like this:

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

At which point, example would equal 2.

2
  • 1
    That duplicate doesn't apply to local variables. It would only work if example were a property. Commented May 18, 2013 at 18:53
  • 2
    Well, that's kind of the point. I take your meaning, however; how about Object with the name of a string? There's also Object name from string in ObjC. Commented May 18, 2013 at 18:56

3 Answers 3

4

You can't do that with local variables like that. You can do it with instance variables using KVC.

Sign up to request clarification or add additional context in comments.

1 Comment

You can actually do that with locals if you really want to, but one would OFC assume that involves servere runtime and macro hackery. There is nothing impossible, only impractical.
2

Contrary to the other answers, if you're willing to go full hack mode, this is indeed possible. Using the power of macros and pointers in C, I have accomplished this task (it also includes information about what type an object is, in case you need to know what to do at run-time).

Use this as a fun example, but be careful - it will increase the amount of memory used quite a bit.

First, let's show how you will be using these APIs:


main.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

You can only look up indexed variables with this example, anything else will simply not be in the lookup table.

2 Comments

It's amazing how this could be reduced to a lookup in a dictionary made with the NSDictionaryOfVariableBindings() macro Apple gave us with AutoLayout ;)
@CodaFi unfortunately that won't work with value types, like mine will.
1

I don't know any language that lets you do that.

In this particular case, you could pass a pointer to the int.

More generally, if you want to manipulate something by its name, use a dictionary:

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

4 Comments

Python provides this kind of rope if you want it (as other interpreted languages probably do): >>> a = 10 >>> locals()['a'] = 12 >>> a 12
As does javascript, you can use eval, as well as several other more complex ways.
Oh yeah, eval - forgot about that sort of thing!
Plenty of varieties of BASIC did that even back in the 1980s.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.