Can a C function be used as a selector in Cocoa?

c, multithreading, objective-c, selector

Solution

Roll your own:

// In some .h file.  #import to make the extension methods 'visible' to your code.
@interface NSThread (FunctionExtension)
+(void)detachNewThreadByCallingFunction:(void (*)(void *))function data:(void *)data;
-(id)initWithFunction:(void (*)(void *))function data:(void *)data;
@end

// In some .m file.
@implementation NSThread (FunctionExtension)

+(void)startBackgroundThreadUsingFunction:(id)object
{
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

  void (*startThreadFunction)(void *) = (void (*)(void *))[[object objectForKey:@"function"] pointerValue];
  void *startThreadData               = (void *)          [[object objectForKey:@"data"] pointerValue];

  if(startThreadFunction != NULL) { startThreadFunction(startThreadData); }

  [pool release];
  pool = NULL;
}

+(void)detachNewThreadByCallingFunction:(void (*)(void *))function data:(void *)data
{
  [[[[NSThread alloc] initWithFunction:function data:data] autorelease] start];
}

-(id)initWithFunction:(void (*)(void *))function data:(void *)data
{
  return([self initWithTarget:[NSThread class] selector:@selector(startBackgroundThreadUsingFunction:) object:[NSDictionary dictionaryWithObjectsAndKeys:[NSValue valueWithPointer:function], @"function", [NSValue valueWithPointer:data], @"data", NULL]]);
}

@end

NOTE: I wrote the above code and here by place it in the public domain. (sometimes the lawyers like this kind of stuff) It is also completely untested!

You can always remove the `NSAutoreleasePool` bits if you can guarantee that the thread entry function also creates one... but it's harmless, has no speed penalty what-so-ever, and makes calling arbitrary C functions that much more simpler. I'd say just keep it there.

And you can use it like so:

void bgThreadFunction(void *data)
{
  NSLog(@"bgThreadFunction STARTING!! Data: %p", data);
}

-(void)someMethod
{
  // init and then start later...
  NSThread *bgThread = [[[NSThread alloc] initWithFunction:bgThreadFunction data:(void *)0xdeadbeef] autorelease];
  // ... assume other code/stuff here.
  [bgThread start];

  // Or, use the all in one convenience method.
  [NSThread detachNewThreadByCallingFunction:bgThreadFunction data:(void *)0xcafebabe];
}

When run:

2009-08-30 22:21:12.529 test[64146:1303] bgThreadFunction STARTING!! Data: 0xdeadbeef
2009-08-30 22:21:12.529 test[64146:2903] bgThreadFunction STARTING!! Data: 0xcafebabe

Problem

I want to start a new thread using a C function, not an objective-C method. I tried ``` [NSThread detachNewThreadSelector: @selector(func) toTarget: nil withObject: id(data)]; ``` where I have ``` void func(void *data) { // ... } ``` and `data` is a `void *`, but I get a runtime crash in `objc_msgSend`, called from ``` -[NSThread initWithTarget:selector:object:] ``` What can I do instead? Is it even possible?

Original source