Is it possible to use the C function as a selector in Cocoa?

I want to start a new thread using the C function, not the objective-C method. I tried

[NSThread detachNewThreadSelector: @selector(func) toTarget: nil withObject: id(data)]; 

where i have

 void func(void *data) { // ... } 

and data is void * , but I get a crash in objc_msgSend called from

 -[NSThread initWithTarget:selector:object:] 

What can I do instead? Is it possible?

+6
c multithreading objective-c selector
source share
5 answers

Collapse by yourself:

 // 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 code above and here in the place of it in the public domain. (sometimes such lawyers like these things) This is also completely untested!

You can always delete the NSAutoreleasePool bits if you can guarantee that the stream input function will also create one ... but it is harmless, has no speed limit anyway, and makes calling arbitrary C functions much easier. I would say just keep it there.

And you can use it like this:

 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]; } 

At startup:

 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 
+10
source share

Create an Objective-C class using a method that simply calls this function. Take the selector of this method and pass it to the NSThread API.

+3
source share

Well, I'm not sure if this is possible, but keep in mind that each Objective-C method has two implicit / hidden arguments, self and _cmd . Usually IMP typedef 'd:

 typedef id (*IMP)(id,SEL,...); 

If you want to use jerry-rig methods and selectors, you must have a method that looks like this:

 void func (id self, SEL _cmd, void *firstParameter); 

But even after that you need to register the name of the selector at runtime, then you need to associate this selector with this method, but this is done on a one-by-one basis (i.e. classes can have different implementations with the same selector name), therefore you at least need to have a dummy class.

It is much easier to just create a dummy class and a dummy instance of this class than call the API at runtime to get NSThread to call a single C function.

+3
source share

If you don't need NSThread stuff, you can also start a thread with a direct POSIX interface .

+1
source share

I want to start a new thread using the C function, not the objective-C method

Then why don't you just use:

  • POSIX streams
  • NOD?

dispatch_async_f() (man) is suitable for this purpose.

0
source share

All Articles