Objective-C to C++ callbacks

As we (Plunge Interactive) are currently working with some cross-platform games with cocos2d-x (c++) that have facebook (native SDK) features we’ve been working on a way of communicating them. In this post I will talk about how we managed to make calls from C++ to Obj-C that throw some events in Obj-C and be able to propagate the events to C++.

As this is a two way trip (C++ -> Obj-C, Obj-C -> C++) and I’m only going to focus on the second part I recommend you to read this post on how to get the first part working.

By now you should be able to make calls to a Objective-C++ “bridge” class that calls Objective-C code. We have (at least!) two options:

  1. Pass a function pointer as parameter to the bridge so it can be called as an event
  2. Pass an object as parameter to the bridge so you can call it’s methods

We’ll start with the first one, that has the limitation that as we don’t have any instance of the class the method has to be static, but it’s easier to implement:

In our c++ normal class from where we will call the bridge functions we have the method to be executed:

class.h:

 static void buttonChoosen(int index); 

class.cpp:

void Class::buttonChoosen(int index)
{
    CCLOG("Button choosen: %d", index);
} 

This method will be called when the user presses a button from the native alert message box. As you can see we use the CCLOG (from cocos2d-x) to make sure the method is executed and gets the pressed button index.

Attention: The following code will be Obj-C++!
iOSHelper.h:

class iOSHelper
{
public:
    void(*callback)(int index);

    iOSHelper() { }
    void ShowAlert(void(*callback)(int));
}; 

As field we store a function pointer that will be passed as parameter to the ShowAlert() method. This function will be executed when the alert Obj-C callback is called.

iOSHelper.mm:

#import "iOSHelper.h"
#import "IsolatedAlert.h"

void iOSBridge::iOSHelper::ShowAlert(void(*callback)(int index))
{
    this->callback = callback;

    IsolatedAlert* instance = [IsolatedAlert new];
    [instance showAlert: this];
}

Notice that we pass as parameter the bridge itself (this) to the showAlert Obj-C method.

IsolatedAlert.h:


#import <UIKit/UIKit.h>
#import "iOSHelper.h"

typedef struct iOSBridge::iOSHelper iOsType;

@interface IsolatedAlert : UIViewController

-(void)showAlert:(iOsType*)callback;

@end 

IsolatedAlert.mm:

#import "IsolatedAlert.h"

iOsType* staticPointer;

@implementation IsolatedAlert

-(void)showAlert:(iOsType*)callback
{
    staticPointer = callback;

    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Title?"
                                                    message:@"Message?"
                                                   delegate:self
                                          cancelButtonTitle:@"Cancel"
                                          otherButtonTitles:@"OK", nil];
    [alert show];
    [alert release];
}

-(void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
    staticPointer->callback(buttonIndex);
}

@end 

Show alert method saves the pointer to the bridge class so the clickedButtonAtIndex method can call the callback to our C++ static method where we can execute our code normally.

That’s all for the first option. For the second one I will not write all the code (as it’s pretty similar), but talk about the differences. Feel free to ask on the comments if anything is not clear enough!

To be able to call an event method we will define an abstract class (in C++) for every task the bridge needs to perform.
For example an AlertCallback.h:

class AlertCallback
{
public:
    void buttonChoosen(int index) = 0;
}; 

If a normal C++ class wants to be able to get the callback from an alert it will need to inherit this class and implement all the methods (this only has one, but a others could require more).

In the bridge we won’t store a function pointer but a pointer to an AlertCallback which is the latest instance that called the showAlert. Notice that polymorphism allow us to have as a field a pointer to an abstract class and store there a pointer to a class that inherits from it.

From the clickedButtonAtIndex method we will be able to call all the member methods of the AlertCallback (only one) as we have a pointer to an instance of it.

And that’s all for this post, have a nice weekend!

5 thoughts on “Objective-C to C++ callbacks

  1. Hey Xavier !
    this is an awesome post, I managed to implement the bridge, and now i can make C++ invoke a UIAlertView !

    I still have a problem that I think you might know how to solve, I implemented your code exactly, but there
    seems to be a problem with this line of code in iOSHelper.mm :

    this->callback = callback;

    it causes EXEC_BAD_ACCESS and crashes the app, as soon as I comment it out the popup appears, but of course crashes after i press a button since there’s no function pointer to callback !

    I’m a total Cpp/obj-c mixing n00b so any tips would help me a lot 🙂

    1. Sorry to flood your comments ;), just fixed the problem, I notice that I didn’t initialize the bridge correctly in my own class that calls the bridge, here’ show it should be done (as any other normal class:D ):

      iOSHelper *myHelper = new iOSHelper();
      myHelper->ShowAlert(settingsScene::buttonChosen);

      Great post !, and btw I found that you are also including the namespace “iOSBridge” but it isn’t declared in the .h file ! hope you can get that fixed as it might confuse people !, cheers ! 🙂

  2. Hi, I am trying to following your example, but when I call staticPointer->callback(buttonIndex), I keep getting EXC_BAD_ACCESS. Do you know why?

  3. This was very helpful! The one thing I usually like to see is how the call is actually made – especially for those that are newer to the language.

    To execute the call you would use the following
    class.cpp (HelloWorld in this case)

    void HelloWorld::buttonChoosen( int index ){
    CCLOG(“Button: %d”, index);
    }

    void HelloWorld::createAlert() {
    iOSBridge::iOSHelper * bridge = new iOSBridge::iOSHelper();
    bridge->ShowAlert( HelloWorld::buttonChoosen );
    }

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s