Search code examples
c++objective-ccallbackcocos2d-x

How to release bridge object after C++ callback is called from Objective C


I'm creating an app in C++ using cocos2d-x. For some integration work, I need to call Objective C code, with an asynchronous response implemented by calling a C++ callback method from Objective C.

TLDR; how should I release the C++ to Objective C bridge whenever the callback finishes? Should I implement the bridge as a static member variable?

For the basic C++ to Objective C part, I've followed Jesús Bosch's lead, for the calling of a C++ callback from Objective C, I've followed his colleagues post.

Basically, I've ended up with the following setup.

First, we have MyApp.h

class MyApp
{
public:
    static void buttonChosen(int index);
    void callObjC();
    // ...
}

and MyApp.cpp, which is responsible for initiating the Objective C code.

void MyApp::buttonChosen(int index)
{
    log("Button choosen: %d", index);
}

void MyApp::callObjC()
{
    iOSBridge::iOSHelper* bridge = new iOSBridge::iOSHelper();
    bridge->ShowAlert(buttonChosen);        
    // delete bridge;
}

Then, I have the bridge, iOSBridge.h

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

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

and its implementation iOSHelper.cpp

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

namespace iOSBridge{    
    void iOSHelper::ShowAlert(void(*callback)(int index))
    {
        this->callback = callback;
    IsolatedAlert* instance = [IsolatedAlert new];
    [instance showAlert: this];
    }
}

Finally, there is the IsolatedAlert.h

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

typedef struct iOSBridge::iOSHelper iOsType;

@interface IsolatedAlert : UIViewController
-(void)showAlert:(iOsType*)callback;
@end

and its implementation 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

Now, my question is this: how should I release iOSBridge::iOSHelper* bridge whenever the buttonChosen() is called? Is implementing it as a static member ok, as long as I promise not to have more than one instance of MyApp instantiated at any one time? Thanks!


Solution

  • The usual C++ way of releasing an instance created with new is to use the delete keyword:

    void MyApp::buttonChosen(int index)
    {
        log("Button choosen: %d", index);
    
        delete bridge;
        bridge = NULL;
    }
    

    It is good practice to NULL the pointer after delete to ensure the application behaves in a consistent manner (crash) in case the object is used after delete. If you don't do that, your application may seem to work for a while, produce incorrect results, show weird behavior, or crash randomly, or all of the aforementioned.

    Ah and of course you should make the bridge pointer a member variable of your App class.

    #include "iOSHelper.h"
    
    class MyApp
    {
    public:
        static void buttonChosen(int index);
        void callObjC();
        // ...
    
    protected:
        iOSBridge::iOSHelper* bridge;
    }
    

    You should also consider making the existing methods protected or private because buttonChosen is probably not a method you want to be able to be called from outside the MyApp instance.