Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to build a NSArray (or NSMutableArray) of class methods in Objective-C?

Tags:

objective-c

I'm trying to build a NSArray of methods in Objective-C.

(What I'm trying to accomplish here is something like the following in C)

typedef (void)(*handler)(int command);

void handleCommandA(void) { ... }
void handleCommandB(void) { ... }

static const handler handler_table[10] = {
    handleCommandA, handleCommandB, handleCommandC
};

I have to port this to Objective-C and I don't know how to build an array of function pointers (in Objective-c world, class methods) at compile-time.

In Objective-C I have the following.

- (void)handleCommandA { ... }
- (void)handleCommandB { ... }

/* Now how to add above 2 functions into NSArray? */
NSArray *handler_table = [NSArray arrayWithObjects:... ];  /* This doesn't seem to work. */
like image 555
jihoonc Avatar asked Feb 22 '09 15:02

jihoonc


People also ask

How do I create an NSArray in Objective-C?

Creating NSArray Objects Using Array Literals In addition to the provided initializers, such as initWithObjects: , you can create an NSArray object using an array literal. In Objective-C, the compiler generates code that makes an underlying call to the init(objects:count:) method.

What is difference between NSArray and NSMutableArray?

The primary difference between NSArray and NSMutableArray is that a mutable array can be changed/modified after it has been allocated and initialized, whereas an immutable array, NSArray , cannot.

What's a difference between NSArray and NSSet?

The main difference is that NSArray is for an ordered collection and NSSet is for an unordered collection. There are several articles out there that talk about the difference in speed between the two, like this one. If you're iterating through an unordered collection, NSSet is great.


2 Answers

The problem here is that to bind those functions you must use the selector keyword which returns a SEL type. This is a pointer type whereas NSArray stores objects.

You thus have three options;

  1. Use a regular C-type array
  2. Fold the functions into an NSObject derived class that will call them.
  3. Use a protocol.

The second is likely the nicer and for this you can use the NSValue class to hold the selector results. E.g;

NSValue* selCommandA = [NSValue valueWithPointer:@selector(handleCommandA:)];
NSValue* selCommandB = [NSValue valueWithPointer:@selector(handleCommandB:)];

NSArray *handler_table = [NSArray arrayWithObjects:selCommandA, selCommandB, nil ];

When you have retrieved the correct entry from the array, to convert back you would do;

SEL mySelector = [selCommand pointerValue];
[someObject performSelector:mySelector];

(Note I'm assuming that from your objective-c syntax that these are intended to be used as methods on an object and not global functions. If you wish to use them globally then you should write them as you would in plain C.)

Another option is to formalize the command methods into a protocol. This allows you to write functionality that will work on any object which implements that protocol and the compiler will provide more checking than if you were just calling selectors.

E.g.

// some header
@protocol CommandHandler
@required
-(void) handleCommandA;
-(void) handleCommandB;
@end

// some other header
@interface someClass : NSObject<CommandHandler>
{
// you will receive compiler warnings if you do not implement the protocol functions
}

Your handling and dispatch code is then written to work with objects of type "CommandHandler". E.g

-(void) registerForCommands:(CommandHandler*)handler
like image 123
Andrew Grant Avatar answered Oct 22 '22 22:10

Andrew Grant


Use NSValue.

For example:

NSArray* handlers = [NSArray arrayWithObjects:[NSValue valueWithPointer:handleA] ... ];

then to access :

handleptr* handle = (handlerptr*)[[handlers objectAtIndex:0] pointerValue];
handle(foo_bar);
like image 30
terry franguiadakis Avatar answered Oct 22 '22 22:10

terry franguiadakis