85

I'm using the iPhone SDK (3.0) and I'm trying to create an array of selectors to invoke a variety of methods within one class.

Obviously, I'm doing something wrong (I think @selector isn't considered a class and so stuffing them into an NSArray isn't working).

I tried this, but it's obviously wrong.

Is there a simple way to have an array of selectors like this? Or is there a better way to iterate through a collection of methods?

selectors = [NSArray arrayWithObjects:
                          @selector(method1),
                          @selector(method2),
                          @selector(method3),
                          @selector(method4),
                          @selector(method5),
                          @selector(method6),
                          @selector(method7), nil];

for (int i = 0; i < [selectors count]; i++) {
    if ([self performSelector:[selectors objectAtIndex:i]]) // do stuff;
}

6 Answers 6

80

Could you store strings and use NSSelectorFromString?

From the docs

NSSelectorFromString

Returns the selector with a given name.

SEL NSSelectorFromString (
   NSString *aSelectorName
);
Sign up to request clarification or add additional context in comments.

2 Comments

Not an appropriate solution for when just an array of selectors is needed.
NSPointerArray is better.
43

This creates an object out of selector:

[NSValue valueWithPointer:@selector(x)]

3 Comments

How would you go about extracting the selector from this to be used by performSelector:?
@DeanKelly answered here stackoverflow.com/questions/575055/… by terry franguiadakis
Type cast is needed, as follows, SEL x = (SEL)selectorValue.pointerValue;
37

Why not just use a simple C array?

static const SEL selectors[] = {@selector(method1),
                                ....
                                @selector(method7)};

...

for (int i = 0; i < sizeof(selectors)/sizeof(selectors[0]); i++) {
  [self performSelector:selectors[i]];
  // ....
}

1 Comment

Good, but static is not needed here (initializer is not a compile-time constant).
13

You can also create an array of NSInvocations. This is handy if you need an argument to go with your selector.

NSMethodSignature *sig = [[yourTarget class] instanceMethodSignatureForSelector:yourSEL];
NSInvocation *inv = [NSInvocation invocationWithMethodSignature:sig];
[inv setTarget:yourTarget];
[inv setSelector:yourSEL];
[inv setArgument:&yourObject atIndex:2]; // Address of your object

1 Comment

NSInvocation is too expensive.
1

If the list is static, I'd go with KennyTM's solution, but if you need a dynamic array or set, another option, besides storing the selector string, is to create an object with an SEL property or ivar, and store that.

@interface SelectorObject : NSObject
@property (assign, readonly, nonatomic) SEL selector;
- (id)initWithSelector:(SEL)selector;
@end

@implementation SelectorObject
- (id)initWithSelector:(SEL)selector {
  self = [super init];
  if (self) {
    _selector = selector;
  }
  return self;
}
@end

You could then add a perform method to the class as well, and implement the method call there.

Comments

1

I'd like to supplement two methods of storing selectors in an array,

First, NSPointerArray can store opaque pointer, such as SEL, as Apple doc said,

NSPointerArray *selectors = [[NSPointerArray alloc] initWithOptions: NSPointerFunctionsOpaqueMemory];
[selectors addPointer:@selector(onSendButton:)];
[button addTarget: self action:[selectors pointerAt:0] forControlEvents:UIControlEventTouchUpInside];

Second, C-style array is much simpler,

SEL selectors[] = { @selector(onSendButton:) };
[button addTarget: self action:selectors[0] forControlEvents:UIControlEventTouchUpInside];

Choose any as you wish.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.