3

I'm trying to implement a dispatch table, so that I can call a selector with the following example code:

NSInteger i = 2;
[myObject performSelector:selectors[i]];

I'm trying to store user preferences which affect which method of an API gets called. Right now, I use the string name of the selector and use NSSelectorFromString, but that's a bit messy. If I use a dispatch table, then I can store an enum instead.

How can I make an array of selectors, or a dispatch table in Objective-C?

Edit:

The compiler complains when I try to set an array of selectors as a property. @property SEL[] won't compile.

Edit2:

I'm using my KosherCocoa API library and I want to call a single method at once, based on a saved user setting. I'm saving to and reading from a Plist file.

Moshe
  • 57,511
  • 78
  • 272
  • 425
  • Instead of doing that, perhaps the Strategy pattern would work better for you. http://en.wikipedia.org/wiki/Strategy_pattern – Nick Toumpelis Dec 19 '11 at 17:21

3 Answers3

3

You can use the SEL type to hold selectors. Simply:

SEL dispatchTable[3] = { @selector(doThis:), 
                         @selector(doThat:), 
                         @selector(doTheOther:) 
                       };

To your edit, use an NSArray/NSDictionary/etc of selectors as your property instead. You are not allowed to use C arrays as properties in Objective C; they are not one of the supported types (which are ObjC objects, CF types and basic C 'Plain Old Data' types.)

OK, on our comments below, you need to wrap the selector in an NSValue to allow you to use it in an objc container (because SEL is a C pointer type):

NSMutableArray * dispatchTable2 = [[NSMutableArray alloc] initWithCapacity:3];
SEL selIn = @selector(doThis:);

// Wrap the selector in an NSValue instance
[dispatchTable2 addObject:[NSValue valueWithPointer:selIn]];

// On extracting:
NSValue * valOut = [dispatchTable2 objectAtIndex:0];
SEL selOut = [[dispatchTable2 objectAtIndex:0] pointerValue];
[anObject performSelector:selOut];

So now your table is an objc container stored as a property or ivar, and you use NSValue to wrap SEL pointers with valueWithPointer: and get the SEL out with pointerValue.

Tim
  • 5,024
  • 2
  • 30
  • 58
  • Actually, there's a problem with using selectors in an array. Doesn't seem to work. I get an "Incompatible pointer" warning. – Moshe Dec 19 '11 at 15:23
  • 2
    Can you post an example of the problem with some code? There's nothing wrong with declaring arrays of selectors. – Tim Dec 19 '11 at 15:26
  • Depends on scope, apparently. When I pasted your array into a method, it was fine, but if I put it into the implementation, outside of a method, it complains. – Moshe Dec 19 '11 at 15:29
  • Thanks, but how do I do this for a hundred pointers. That can get messy really fast, no? – Moshe Dec 19 '11 at 16:15
  • A hundred selectors? What are you trying to build? Just in case it's not perfectly obvious you don't need to explicitly declare a hundred SEL variables; you can do the whole thing dynamically: [table addObject:[NSValue valueWithPointer:@selector(doThis:)]]; but ultimately if you have a hundred selectors, somewhere you're going to have to name them. – Tim Dec 19 '11 at 16:38
2

I would recommend using NSInvocation instead of selectors. They are far more flexible, as you can send the same invocation to many objects and you can change its properties as you go.

Nick Toumpelis
  • 2,717
  • 22
  • 38
1

One way to do this is using an array of NSStrings, then converting those to SELs at runtime, if that increases readability for you..

NSString *selectors[] = { ... } 

[myObject performSelector:NSSelectorFromString(selectors[i])];

To use this as a property, use

@property(nonatomic, assign) NSString **selectors;
Richard J. Ross III
  • 55,009
  • 24
  • 135
  • 201
  • just for the record, I tried using `@property(nonatomic, assign) NSString **selectors;` it gives error `pointer to non-const type NSString *with no explicit ownership` while `@property(nonatomic, assign) void **selectors;` works – geekay Aug 08 '14 at 10:44