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.

mmmmmm
  • 32,227
  • 27
  • 88
  • 117
Kerberos
  • 4,036
  • 3
  • 36
  • 55
  • 1
    That duplicate doesn't apply to local variables. It would only work if `example` were a property. – rmaddy May 18 '13 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](http://stackoverflow.com/q/6164134)? There's also [Object name from string in ObjC](http://stackoverflow.com/q/3888935). – jscs May 18 '13 at 18:56

3 Answers3

4

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

DrummerB
  • 39,814
  • 12
  • 105
  • 142
  • 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. – Richard J. Ross III May 18 '13 at 18:57
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.

Richard J. Ross III
  • 55,009
  • 24
  • 135
  • 201
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);
matt
  • 515,959
  • 87
  • 875
  • 1,141