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.
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.
You can't do that with local variables like that. You can do it with instance variables using KVC.
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.
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);