0

I've got an array that contains the name of a function and a parameter that looks something like this.

(
    [0] => (
        [0] => @"getName"
        [1] => @"This is the name"
    )
)

and for my method, it looks something like this.

-(NSString *)getName:(NSString *)name {...}

I know to trigger a method I would have to do [[AppDelegate alloc] getName:string]; but would there be any way to substitute getName with array[0][0] and string with array[0][1]?

SteppingHat
  • 1,199
  • 4
  • 19
  • 50
  • Do you want to substitute the string in for a function or an object? You say "function", but then you say you want to replace `AppDelegate` with a string. – sudo Jun 03 '14 at 02:24
  • Oops. My bad. I want to replace `getName` with `array[0][0]` and `string` with `array [0][1]`. Edited question to fix – SteppingHat Jun 03 '14 at 02:29
  • is this meant to be for cases in where you cannot know the name of the function beforehand? or do you already know all the possible functions? – Pochi Jun 03 '14 at 02:49

3 Answers3

2

What you are doing here is a bit dangerous. Anyways you achieve this by using selectors.

Objects adopt a protocol that tells them if they can perform certain actions. So basically, you have to first get the strings for the function and the argument out of the array.

Then you create a selector by using the function that allows it to be called at runtime.

SEL aSelector = NSSelectorFromString(@"methodName");

Then, ASK if your object can perform the selector (if you just blindly send it bad things can happen)

- (BOOL)respondsToSelector:(SEL)aSelector

And finally you can perform the selector with the object that you previously got (this is the argument).

- (id)performSelector:(SEL)aSelector withObject:(id)anObject

See this for selectors: https://developer.apple.com/library/ios/documentation/General/Conceptual/DevPedia-CocoaCore/Selector.html

And this for the object protocol: https://developer.apple.com/library/ios/documentation/cocoa/reference/foundation/Protocols/NSObject_Protocol/Reference/NSObject.html#//apple_ref/occ/intfm/NSObject/respondsToSelector:

Edit: As danh mentions, it is important for the selector name to have a trailing colon, since your method accepts an argument. If there was no argument being passed you wouldn't need it.

Since

- (id)doSomething;

is different to

- (id)doSomething:(id)argument;
Pochi
  • 13,391
  • 3
  • 64
  • 104
2

Since you need to pass in argument and get return value, use NSInvocation. More details here NSInvocation for Dummies?

For NSInvocation's set Selector, you can set the selector as NSSelectorFromString(array[0][0]); Similarly for argument and return values.

Community
  • 1
  • 1
nprd
  • 1,942
  • 1
  • 13
  • 16
1

Here's a working example of @Chiquis idea. (note that your selector needs a trailing colon):

-(void)doSomethingALittleDangerous
    NSArray *array = @[@[@"getName", @"this is the name"]];

    NSString *notQuiteTheSelectorStr = array[0][0];
    NSString *selectorStr = [notQuiteTheSelectorStr stringByAppendingString:@":"];

    SEL selector = NSSelectorFromString(selectorStr);

    // this generates a warning because the compiler cannot confirm that
    // self implements this programmatically derived selector
    if ([self respondsToSelector:selector]) {
        NSString *name = [self performSelector:selector withObject:array];
    }
    NSLog(@"%@", name);
}

- (NSString *)getName:(NSArray *)array {
    return array[0][1];
}
danh
  • 62,181
  • 10
  • 95
  • 136
  • Yes, forgot about that, without the colon it is a different method. – Pochi Jun 03 '14 at 07:17
  • Thanks! This is just what I was looking for. I was exploring @Chiquis idea but since I'm new to obj-c it I wasn't able to get a working version on my own. This is perfect. Thanks! :) – SteppingHat Jun 03 '14 at 11:18
  • You wouldn't happen to know the flag to ignore that warning would you? I know if I were to disable warnings about unused paramaters for example I would use `-Wno-unused-parameter` – SteppingHat Jun 03 '14 at 13:06