Calling Objective-C Method from C++ Member Function

Calling Objective-C method from C++ member function?

You can mix C++ with Objective-C if you do it carefully. There are a few caveats but generally speaking they can be mixed. If you want to keep them separate, you can set up a standard C wrapper function that gives the Objective-C object a usable C-style interface from non-Objective-C code (pick better names for your files, I have picked these names for verbosity):

MyObject-C-Interface.h

#ifndef __MYOBJECT_C_INTERFACE_H__
#define __MYOBJECT_C_INTERFACE_H__

// This is the C "trampoline" function that will be used
// to invoke a specific Objective-C method FROM C++
int MyObjectDoSomethingWith (void *myObjectInstance, void *parameter);
#endif

MyObject.h

#import "MyObject-C-Interface.h"

// An Objective-C class that needs to be accessed from C++
@interface MyObject : NSObject
{
int someVar;
}

// The Objective-C member function you want to call from C++
- (int) doSomethingWith:(void *) aParameter;
@end

MyObject.mm

#import "MyObject.h"

@implementation MyObject

// C "trampoline" function to invoke Objective-C method
int MyObjectDoSomethingWith (void *self, void *aParameter)
{
// Call the Objective-C method using Objective-C syntax
return [(id) self doSomethingWith:aParameter];
}

- (int) doSomethingWith:(void *) aParameter
{
// The Objective-C function you wanted to call from C++.
// do work here..
return 21 ; // half of 42
}
@end

MyCPPClass.cpp

#include "MyCPPClass.h"
#include "MyObject-C-Interface.h"

int MyCPPClass::someMethod (void *objectiveCObject, void *aParameter)
{
// To invoke an Objective-C method from C++, use
// the C trampoline function
return MyObjectDoSomethingWith (objectiveCObject, aParameter);
}

The wrapper function does not need to be in the same .m file as the Objective-C class, but the file that it does exist in needs to be compiled as Objective-C code. The header that declares the wrapper function needs to be included in both CPP and Objective-C code.

(NOTE: if the Objective-C implementation file is given the extension ".m" it will not link under Xcode. The ".mm" extension tells Xcode to expect a combination of Objective-C and C++, i.e., Objective-C++.)


You can implement the above in an Object-Orientented manner by using the PIMPL idiom. The implementation is only slightly different. In short, you place the wrapper functions (declared in "MyObject-C-Interface.h") inside a class with a (private) void pointer to an instance of MyClass.

MyObject-C-Interface.h (PIMPL)

#ifndef __MYOBJECT_C_INTERFACE_H__
#define __MYOBJECT_C_INTERFACE_H__

class MyClassImpl
{
public:
MyClassImpl ( void );
~MyClassImpl( void );

void init( void );
int doSomethingWith( void * aParameter );
void logMyMessage( char * aCStr );

private:
void * self;
};

#endif

Notice the wrapper methods no longer require the void pointer to an instance of MyClass; it is now a private member of MyClassImpl. The init method is used to instantiate a MyClass instance;

MyObject.h (PIMPL)

#import "MyObject-C-Interface.h"

@interface MyObject : NSObject
{
int someVar;
}

- (int) doSomethingWith:(void *) aParameter;
- (void) logMyMessage:(char *) aCStr;

@end

MyObject.mm (PIMPL)

#import "MyObject.h"

@implementation MyObject

MyClassImpl::MyClassImpl( void )
: self( NULL )
{ }

MyClassImpl::~MyClassImpl( void )
{
[(id)self dealloc];
}

void MyClassImpl::init( void )
{
self = [[MyObject alloc] init];
}

int MyClassImpl::doSomethingWith( void *aParameter )
{
return [(id)self doSomethingWith:aParameter];
}

void MyClassImpl::logMyMessage( char *aCStr )
{
[(id)self doLogMessage:aCStr];
}

- (int) doSomethingWith:(void *) aParameter
{
int result;

// ... some code to calculate the result

return result;
}

- (void) logMyMessage:(char *) aCStr
{
NSLog( aCStr );
}

@end

Notice that MyClass is instantiated with a call to MyClassImpl::init. You could instantiate MyClass in MyClassImpl's constructor, but that generally isn't a good idea. The MyClass instance is destructed from MyClassImpl's destructor. As with the C-style implementation, the wrapper methods simply defer to the respective methods of MyClass.

MyCPPClass.h (PIMPL)

#ifndef __MYCPP_CLASS_H__
#define __MYCPP_CLASS_H__

class MyClassImpl;

class MyCPPClass
{
enum { cANSWER_TO_LIFE_THE_UNIVERSE_AND_EVERYTHING = 42 };
public:
MyCPPClass ( void );
~MyCPPClass( void );

void init( void );
void doSomethingWithMyClass( void );

private:
MyClassImpl * _impl;
int _myValue;
};

#endif

MyCPPClass.cpp (PIMPL)

#include "MyCPPClass.h"
#include "MyObject-C-Interface.h"

MyCPPClass::MyCPPClass( void )
: _impl ( NULL )
{ }

void MyCPPClass::init( void )
{
_impl = new MyClassImpl();
}

MyCPPClass::~MyCPPClass( void )
{
if ( _impl ) { delete _impl; _impl = NULL; }
}

void MyCPPClass::doSomethingWithMyClass( void )
{
int result = _impl->doSomethingWith( _myValue );
if ( result == cANSWER_TO_LIFE_THE_UNIVERSE_AND_EVERYTHING )
{
_impl->logMyMessage( "Hello, Arthur!" );
}
else
{
_impl->logMyMessage( "Don't worry." );
}
}

You now access calls to MyClass through a private implementation of MyClassImpl. This approach can be advantageous if you were developing a portable application; you could simply swap out the implementation of MyClass with one specific to the other platform ... but honestly, whether this is a better implementation is more a matter of taste and needs.

Calling an Objective-C class method from C++

Objects in C++ are incompatible with objects in Objective-C. You cannot simply call an Objective-C method from C++.

There are some solutions, however:

  1. Use Objective-C++. Rename your .cpp to .mm, then you can use Objective-C syntax in your C++ code: [FlurryAnalytics myMethod: @"foo"];

  2. Use direct calls to the Objective-C runtime system. I won't tell you how to, because I really think you shouldn't, and in fact that you don't want to.

  3. Write a plain-C interface. That is, in some .m file, define void myFunction(const char *str) { ... } and call that from C++. You can find an example of this here.

Pure C function calling Objective-C method?

After much experimenting, I found that the most elegant way of solving my problem was to turn my core C library into an NSObject using the .m suffix. The method of calling back and forth resolved instantly. This change DOES alter my original library, but by so little, it's manageable. So to review:

My original C file was renamed to use the .m suffix. Then I added

@interface myCLibrary : NSObject

@end

to my .h file, and added to my formerly .c file, now renamed .m.

@implementation myCLibrary

@end

Just remember that C functions aren't to be pasted between these interface / implementation declarations, below them. Only Objective-C is to go inside these statements. Once I did that, calling the C functions, and calling BACK to other C functions worked great.

Thanks for all the help regardless.

How to call an Objective-C Method from a C Method?

In order for that to work, you should define the C method like this:

void cMethod(id param);

and when you call it, call it like this:

cMethod(self);

then, you would be able to write:

[param objcMethod];

In your cMethod.

This is because the self variable is a special parameter passed to Objective-C methods automatically. Since C methods don't enjoy this privilege, if you want to use self you have to send it yourself.

See more in the Method Implementation section of the programming guide.

Calling an objective c method using a function pointer from a c++ method

The problem is that the function signature of Objective-C methods is not as simple as you might think.

In order to make object-oriented programming possible, Objective-C methods take two implicit arguments: id self, SEL _cmd, the calling object and the selector sent - these need to be passed. You will need to get an object to call the method on, and you should store the selector too. Then, change your function type definition to the correct one:

typedef void (*FuncPtr) (id, SEL, status);

To be read: [1], [2] (near the part typedef id (*IMP)(id, SEL, ...))

Calling Objective-C method from C++ method? [2]

i mean, i cannot cast to MyObject or otherwise let the compiler know, what method to call

Why not?

Your C++ wrapper class must be in an Objective-C++ file (usually denoted with the .mm) extension. Then, because you even have to declare your private instance variables in the class declaration, you need a private member to hold the Objective-C pointer in the class header. This must be something that a pure C++ compiler can understand so one thing you could do is this:

#ifndef __MYOBJECT_C_INTERFACE_H__
#define __MYOBJECT_C_INTERFACE_H__ 1

#if defined __OBJC__
typedef id MyObjCClass;
#else
typedef void* MyObjCClass;
#endif

struct CWrap {
MyObjCClass myObjectInstance;
int MyObjectDoSomethingWith (void *parameter);
}

Then in the .mm file

#import "ObjCClassHeader.h"

int CWrap::MyObjectDoSomethingWith(void *parameter)
{
return [myObjectInstance doSomethingWith: parameter];
}

__OBJC__ is a predefined macro that is defined when the compiler is compiling Objective-C or Objective-C++

C function vs. Objective-C method?

Actually, an Objective-C method is just a C function with two arguments always present at the beginning.

This:

-(void)aMethod;

Is exactly equivalent to this:

void function(id self, SEL _cmd);

Objective-C's messaging is such that this:

[someObject aMethod];

Is exactly equivalent to this (almost -- there is a variadic argument ABI issue beyond the scope of this answer):

objc_msgSend(someObject, @selector(aMethod));

objc_msgSend() finds the appropriate implementation of the method (by looking it up on someObject) and then, through the magic of a tail call optimization, jumps to the implementation of the method which, for all intents and purposes, works exactly like a C function call that looks like this:

function(someObject, @selector(aMethod));

Quite literally, Objective-C was originally implemented as nothing but a C preprocessor. Anything you can do in Objective-C could be rewritten as straight C.

Doing so, however, would be a complete pain in the ass and not worth your time beyond the incredibly educational experience of doing so.


In general, you use Objective-C methods when talking to objects and function when working with straight C goop. Given that pretty much all of Mac OS X and iOS provide Objective-C APIs -- certainly entirely so for the UI level programming entry points -- then you use Obj-C most of the time.

Even when writing your own model level code that is relatively standalone, you'll typically use Objective-C simply because it provides a very natural glue between state/data & functionality, a fundamental tenant of object oriented programming.



Related Topics



Leave a reply



Submit