Reputation: 111
I'm writing a game for the iPhone. Almost all the code is written in C++. Now I'd like to create a new thread using NSThread (I want to use the runLoop).
It's possible to mix objective-C and C++ if the code is written in a .mm file, which I did.
The problem is, that for creating a NSThread
NSThread* myThread = [[NSThread alloc] initWithTarget:self selector:@selector(workerThreadFunction:) object:nil];
[myThread start];
I need to pass "self" which (as far as I understand it) an Objective-C "id" - and a c++ object is not an objective-c object.
So - is there a way to use NSThread in a c++ aplication or am I forced to use pthreads?
Thanks!
Upvotes: 3
Views: 2568
Reputation: 36141
"can I somehow create an objective-C object which - in it's constructor - takes a c++ function pointer as an argument which it calls later?"
Yes, but its rather ugly.
First, define a callback baseclass, and a templated version. This can go into a generic .h file that can be #includ
ed from .cpp and .mm files. Also define a basic CThread
class:
// Thread.h
#pragma once
#include <objc/objc.h> // for a cpp compatible definition of id
class Callback{
public:
virtual void operator()(void)=0;
};
template<class T>
class ClassCallback : public Callback {
T* _classPtr;
typedef void(T::*fncb)(void);
fncb _cbProc;
public:
ClassCallback(T* classPtr,fncb cbProc):_classPtr(classPtr),_cbProc(cbProc){}
virtual void operator()(void){
(_classPtr->*_cbProc)();
}
};
class CThread {
id _thread;
public:
void Start(Callback* cb);
};
Next, put the implementation of CThread
, and its obj-c buddy object, in a .mm file:
// Thread.mm
#import <Cocoa/Cocoa.h>
#import "Thread.h"
@interface ThreadStarter:NSObject
{
Callback *theCallback;
}
-(void)Run;
-(id)init:(Callback*)cb;
@end
@implementation ThreadStarter
-(id)init:(Callback*)cb
{
theCallback = cb;
return [super init];
}
-(void)Run
{
theCallback();
}
@end
void CThread::Start(Callback* cb){
_thread = [[ThreadStarter alloc] init:cb];
[NSThread detachNewThreadSelector:@selector(Run)
toTarget:_thread
withObject:nil];
}
};
And then, in your application's cpp file, you can:
// MyClass.cpp (doesn't even have to be .mm)
#include "Thread.h"
class MyClass {
CThread _myThread;
void SomeArbMethod(){
}
public:
MyClass(){
_myThread.Start( new ClassCallback<MyClass>(this,&MyClass::SomeArbMethod));
}
};
Upvotes: 1
Reputation: 61398
For a C++-style rephrasing of my previous answer:
//The C++ base
class ThreadBase
{
virtual void Run() = 0;
};
//The ObjC wrapper
@interface ThreadStarter:NSObject
{
ThreadBase *TheThread;
}
-(void)Run;
-(id)init:(ThreadBase)tb;
@end
@implementation ThreadStarter
-(id)init:(ThreadBase)tb
{
TheThread = tb;
return [super init];
}
-(void)Run
{
TheThread->Run();
}
@end
//
class MyThread: public ThreadBase
{
//...
};
//And finally usage
MyThread *Thread = new MyThread();
ThreadStarter *tc = [[ThreadStarter alloc]init:Thread];
NSThread* myThread = [[NSThread alloc] initWithTarget:tc selector:@selector(Run) object:nil];
[myThread start];
Much cleaner this way, IMHO. If you're insist that the thread start routine is an arbitrary function in an atrbitrary class not of your creation, here's your answer:
class MyThread: public ThreadBase, public MyOtherObject
{
void Run()
{
DoWork(); //Function defined in MyOtherObject
}
}
You see, if you want to parametrize by member function, you have to parametrize by both function and class. And class cannot be a run-time variable in C++.
Upvotes: 0
Reputation: 61398
can I somehow create an objective-C object which - in it's constructor - takes a c++ function pointer as an argument which it calls later?
Sure. Like this:
//The C++ base
class ThreadBase
{
virtual void Run() = 0;
};
typedef ThreadBase * (*ThreadCreator)();
//The ObjC wrapper
@interface ThreadStarter:NSObject
{
ThreadCreator TheCreator;
}
-(void)Run;
-(id)init:(ThreadCreator)tc;
@end
@implementation ThreadStarter
-(id)init:(ThreadCreator)tc
{
TheCreator = tc;
return [super init];
}
-(void)Run
{
(*TheCreator)()->Run();
}
@end
//
class MyThread: public ThreadBase
{
//...
};
ThreadBase *MyThreadCreator()
{
return new MyThread();
}
//And finally usage
ThreadStarter *tc = [[ThreadStarter alloc]init:MyThreadCreator];
NSThread* myThread = [[NSThread alloc] initWithTarget:tc selector:@selector(Run) object:nil]; [myThread start];
It's parametrized by a creator function because you wanted it so. But you can parametrize by class as well.
Upvotes: 2
Reputation: 61398
You cannot derive C++ classes from Objective C classes and vice versa. Design a wrapper ObjC object that would instantiate and call (but not inherit from) the C++ one. This is generally called "containment and delegation".
Or you can use POSIX threads instead of NSThread.
Upvotes: 0