Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

l0uismustdie

macrumors regular
Original poster
Nov 30, 2009
109
1
Edinburgh, UK
I am wondering if anyone has any ideas how I might be able to store a function as the object in an NSDictionary. I know in python this can be done with something like:
Code:
dictName={"key",function_name}
But I am not sure how something like this could be accomplished in objective c.

Thanks in advance.
 
C function or selector?

Since selectors can be made from strings

SEL NSSelectorFromString(NSString *aSelectorName);
and
NSString *NSStringFromSelector( SEL aSelector );

so...

Code:
NSDictionary *selectorDict = [NSDictionary dictionaryWithObjectsAndKeys: NSStringFromSelector(@selector(addObject:)), @"addObjectKey", nil];

//And then later...
[object perforSelector: NSSelectorFromString( [selectorDict objectForKey: @"addObjectKey"] )];

Though off the top of my head I cannot think of any specific practical use of doing this...
For C-Functions I would guess that it can be done with NSValue and function pointers.
 
Whilst the above will work it would also probably be sensible to store the instance you intend to call the selector on. Without an object to call on the selector on it's own is not all that much use. If you want to wrap up the entire thing as a single object you could use an NSInvocation and encode that with a NSCoder.

I must admit I assumed that we were talking about C functions as the OP said "function", not method.
 
Because he was interested in storing it in an NS collection class I kinda assumed he MIGHT be talking about selectors instead of C functions.

HYPOTHETICALLY------
lets say we have a function named and defined like
int add(int a, int b) { return (a+b); }

We can define a pointer to it like..

int (*function)(int a, int b) = &add;

Now if we put this pointer into an instance of NSValue and stored it in an array it would sorta be like putting the function add(int a, int b) into that array.

Now you can certainly make C arrays of these, and reference them by index. So I would think you could store the "address" of a function for later use... though I cannot think of a reason why off the top of my head. Other than to implement object oriented programming in C.
 
Whilst the above will work it would also probably be sensible to store the instance you intend to call the selector on. Without an object to call on the selector on it's own is not all that much use. If you want to wrap up the entire thing as a single object you could use an NSInvocation and encode that with a NSCoder.

I must admit I assumed that we were talking about C functions as the OP said "function", not method.

No need for the NSCoder — just put the NSInvocation directly in the dictionary.

Separately, to build on what jared_kipe was saying (ummm, sort of), a SEL is a C type (almost certainly a typedef of some sort of pointer, but I can't find any guarantee), so you should be able to take a pointer to one and store that in an NSValue.
 
I think this discussion would probably benefit from an explanation from the OP as to why he wants to do this. I would bet that there is something the OP hasn't thought of that would get us around the whole function in collection class problem.
 
Isn't this what blocks is for? From what I understand blocks are used to encapsulate code as objects.

Code:
NSDictionary *dict = [[NSDictionary alloc] initWithObjectsAndKeys:
	^(double p) { return (p + 2); }, @"addTwo",
	^(double p) { return (p * 3); }, @"mulThree",
	^(double p) { return sqrt(p); }, @"root",
nil];
	
double x = 2.5;
for (id key in dict) {
	double (^func)(double) = [dict objectForKey:key];
	NSLog(@"%@: %f", key, func(x));
}
 
Ok so I cheat, but you could either put the NSPointerArray into a dictionary with a key, or just use the NSPointerArray instead of a dictionary.

Code:
#import <Foundation/Foundation.h>
int add(int a, int b){ return (a+b); }
int (*function)(int a, int b) = NULL;

int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
	
	NSPointerArray *pointerArray = [NSPointerArray pointerArrayWithWeakObjects];
	[pointerArray addPointer: &add];
	
	function = [pointerArray pointerAtIndex:0];
	int a,b;
	a = 2;
	b = 5;
	NSLog(@"a = %d, b = %d, function(a,b) = %d", a, b, (*function)(a,b) );
	
    [pool drain];
    return 0;
}

C function put into an array! *BAM*
 
-[NSValue valueWithPointer:] ?

Don't know why I didn't take my own advice and look into NSValue, mainly because I've only used NSValue with point and @encode.

So slight modification to prior code
Code:
#import <Foundation/Foundation.h>
int add(int a, int b){ return (a+b); }
int (*function)(int a, int b) = NULL;

int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
	
	NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
						  [NSValue valueWithPointer: &add], @"addFunctionKey", nil];

	function = [[dict objectForKey: @"addFunctionKey"] pointerValue];
	int a,b;
	a = 2;
	b = 5;
	NSLog(@"a = %d, b = %d, function(a,b) = %d", a, b, (*function)(a,b) );
	
    [pool drain];
    return 0;
}
 
Thanks everyone for your posts. I suppose I should give out some more info..sorry the first post was so vague. It looks like I am actually trying to store a method in the dictionary. Excuse my lapse in terminology...I am new to objective c and actually rarely do OO programming. Here is the full situation:
I am essentially mimicking a symbol table. So I have a dictionary of what would represent the symbol table, let's call it symboltable. This stores memory address as the key and the symbol as the object. Let's say for example I come across the symbol "boinc_init". What I want to be able to do is look for this symbol in a dictionary of known_symbols which contains each symbol as a key and the method it should run as a value.
I know this can easily be done by some conditional statements...I am just trying to be fancy.
So I have a virtual machine class that contains all of my methods. Let's say that I have a method "dummy" declared. If I find "boinc_init" at my current location inside my symboltable dictionary I want to run this dummy method.

I hope this makes a little more sense...and sorry for saying function.

Just realized these might help as well:
This is the dummy function:
Code:
-(NSDictionary*)dummy:(NSMutableDictionary *)memory atIP:(unsigned long)IP withRegs:(NSMutableArray *)reg andSymbolTable:(NSMutableDictionary *)symboltable
{
	NSDictionary			*returnDict;
	NSLog(@"Dummy function. Nothing happens");
	[returnDict setValue:memory forKey:@"memory"];
	[returnDict setValue:reg forKey:@"reg"];
	return returnDict;
}
This is where I am trying to call it. I haven't implemented the comparison between the current location in the symboltable (IP) and the known_symbols
Code:
-(NSDictionary*)boinccall:(NSMutableDictionary *)memory atIP:(unsigned long)IP withRegs:(NSMutableArray *)reg andSymbolTable:(NSMutableDictionary *)symboltable
{
	NSDictionary		*returnDict;
	NSDictionary		*known_symbols=??????

	return returnDict;
	
}
So, just maybe in recap. boinccall() gets called and it should compare symboltable[IP] with the known_symbols, which should be no problem. The real question is: if symboltable[IP] is in the known_symbols dictionary how can it use that to run a specific function.

I hope this all helps and doesn't hinder.
 
My very first reply should have what you need. (it sounds like)

Every objective-C method is defined by a @selector(methodName)

You can make a selector from a NSString instance so store the NSString that describes the method in your array.

One of the polymorphisms of objective-c is that you can dispatch a selector at runtime via

[object performSelector: selector];

Here are some ways to make a selector.
@selector(methodName:andArgument:)
NSSelectorFromString( (NSString *)stringObject )

EDIT:
It sounds like you maybe don't know how to tell if a NSDictionary has a key. If you ask a dictionary for objectForKey: key and key isn't in the dictionary it will return nil. So you can either just message nil, or test to see if the return is nil.
 
Almost there I think...
Here is what I have so far:
Code:
NSDictionary	*known_symbols=[NSDictionary dictionaryWithObjectsAndKeys:NSStringFromSelector(@selector(dummy:)),@"boinc_init",NSStringFromSelector(@selector(dummy:)),@"_start",nil];
	
if([known_symbols objectForKey:[symboltable objectForKey:[NSString stringWithFormat:@"%u",IP]]])
{
        NSLog(@"Symbol Identified. Running substitute function.");
	returnDict=[self performSelector:NSSelectorFromString([known_symbols objectForKey:[symboltable objectForKey:[NSString stringWithFormat:@"%u",IP]]])withObject:memory withObject:[NSNumber numberWithUnsignedLong:IP]];
}
This is giving me the error:
Code:
2010-06-30 11:44:57.132 vm[11588:207] *** -[virtual_machine_32 dummy:]: unrecognized selector sent to instance 0x3915b50
Also, it looks like there is only a performSelector:withObject:withObject. I need to send 4 objects in this case any thoughts on that?

jared...thanks a lot for your help.
Also, finding whether or not the key is in the dictionary isn't a problem. My problem really is just using selectors like this.
 
This

Code:
@selector(dummy:)

doesn't match this

Code:
-(NSDictionary*)dummy:(NSMutableDictionary *)memory atIP:(unsigned long)IP withRegs:(NSMutableArray *)reg andSymbolTable:(NSMutableDictionary *)symboltable

Look at NSInvocation to call methods with 4 objects.
 
Also, it looks like there is only a performSelector:withObject:withObject. I need to send 4 objects in this case any thoughts on that?

Define a single class that encapsulates your multiple parameters (tuples): memory, instruction pointer, registers, and symbols. Name it MyVirtualMachine. Then you can condense all your multiple-parameter methods into ones that take a single object containing all the necessary context, i.e. the virtual machine itself.

This is a perfect example of when to create an object instead of passing multiple parallel parameters. Really, when will the instruction ptr, memory, or registers ever be used in isolation, i.e. separated from the rest of the vm context?
 
Bingo! Yeah I think I got what I'm looking for. Thanks again everyone. Here is my final result:
Code:
NSDictionary		*returnDict;
NSDictionary		*known_symbols=[NSDictionary dictionaryWithObjectsAndKeys:NSStringFromSelector(@selector(dummy:)),@"boinc_init",NSStringFromSelector(@selector(dummy:)),@"_start",nil];
Parameters		*toSend=[Parameters new];
toSend.memory=memory;
toSend.IP=[NSNumber numberWithUnsignedLong:IP];
toSend.reg=reg;
toSend.symbol_table=symboltable;

if([known_symbols objectForKey:[symboltable objectForKey:[NSString stringWithFormat:@"%u",IP]]])
{
	NSLog(@"Symbol Identified. Running substitute function.");
	returnDict=[self performSelector:NSSelectorFromString([known_symbols objectForKey:symboltable objectForKey:[NSString stringWithForat:@"%u",IP]]])withObject:toSend];
	return returnDict;
}
 
Define a single class that encapsulates your multiple parameters (tuples): memory, instruction pointer, registers, and symbols. Name it MyVirtualMachine. Then you can condense all your multiple-parameter methods into ones that take a single object containing all the necessary context, i.e. the virtual machine itself.

This is a perfect example of when to create an object instead of passing multiple parallel parameters. Really, when will the instruction ptr, memory, or registers ever be used in isolation, i.e. separated from the rest of the vm context?

Agreed, you should never need to send more than 1 object unless it is in some way super convenient to send several.

You can either pass it an array, or a custom object with members that you setup on your own.

If you decide to send it an array, do yourself a favor and setup an enumerated type to say what index does what, such as...
Code:
typedef enum {
	kMemoryIndex = 0,
	kIPIndex,
	kRegIndex,
	kSymbolTableIndex
} ParameterType;
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.