如何为cpp类创建一个objective-c委托?

时间:2012-12-23 05:27:42

标签: ios opengl-es-2.0 powervr-sgx

我一直试图将openGL-es(xcode openGL游戏模板与powervr 3.0 sdk中的ogles2tools库结合起来。我的问题是加载效果文件的代码行:

/* 
 Load the effect.
 We pass 'this' as an argument as we wish to receive callbacks as the PFX is loaded.
 This is optional and supplying NULL implies that the developer will take care
 of all texture loading and binding to to the Effect instead.
*/
if(m_pEffect->Load(*m_pEffectParser, "Effect", c_szPfxFile, NULL, uiUnknownUniforms, &error) != PVR_SUCCESS)
{
    NSLog(@"%s",error.c_str());
    return;
}

我应该传递一个“this”指针,这样我就可以收到回调。我需要实现的委托方法是:

EPVRTError OGLES2IntroducingPFX::PVRTPFXOnLoadTexture(const CPVRTStringHash& TextureName, GLuint& uiHandle, unsigned int& uiFlags)
{
    /*
     This is an optional callback function for PVRTPFXEffect and can be used to automate 
     the texture loading process.
     If multiple effects are to be loaded and they share textures it would be
     prudent to have a caching system in place so texture memory is not wasted.
     Please see OGLES2MagicLantern for an example of this.
    */
    if(PVRTTextureLoadFromPVR(TextureName.String().c_str(), &uiHandle) != PVR_SUCCESS)
    return PVR_FAIL;

    return PVR_SUCCESS;
}

我想对我来说最重要的问题是如何在objective-c中提供cpp委托方法?我在这个问题上做了一些阅读,但看起来我正在读的是另一回事。也就是说,cpp中的objective-c委托。这很令人困惑,但这是我的想法......

我创建了一个cpp类,实现了我需要的方法。我将它添加到我的viewController类,并将指针传递给m_pEffect->加载调用中的此cpp类。这看起来是否正确?

感谢。

P.S。对不起,如果我的代码格式不好。我还在学习。

编辑: Here's the example我发现混合了Objective-c和cpp。它看起来与我想做的非常相似。

更新:以下是其他一些信息(user1118321要求)

需要委托的CPP类是CPVRTPFXEffect(PVRTPFXParserAPI.h - 来自powerVR SDK 3.0)。我会添加一个链接,但我不确定是否允许这样做。 Here's a link 到类标题,但此版本(以及Web上的其他版本)不包含load方法的pDelegate属性。我假设他们是以前版本的例子。让我知道是否可以发布这个类文件,我会这样做。

我发现了good example我想我应该通过阅读this thread做的事情。所以这就是我到目前为止所做的:

我的CPP代表班......

    class myCppDelegate : public PVRTPFXEffectDelegate {
public:
    myCppDelegate() {};
    EPVRTError PVRTPFXOnLoadTexture(const CPVRTStringHash& TextureName, GLuint& uiHandle, unsigned int& uiFlags) { 
        return PVR_FAIL; 
    };

};

我的Obj-C包装类(刚从上面的示例链接中修改过)...

struct RNWrapOpaque;

@interface RNWrap : NSObject {
struct RNWrapOpaque *_cpp;
}

- (id)init;
@end

...实施

#import "RNWrap.h"
#import "Wrap.h"

@interface RNWrap ()
@property (nonatomic, readwrite, assign) RNWrapOpaque *cpp;
@end

@implementation RNWrap
@synthesize cpp = _cpp;


struct RNWrapOpaque
{
public:
    RNWrapOpaque() : wrap() {};
    myCppDelegate wrap;
};

- (id)init
{
    self = [super init];
    if (self != nil)
    {
        self.cpp = new RNWrapOpaque();
    }
    return self;
}

- (void)dealloc
{
    delete _cpp;
    _cpp = NULL;

//  [super dealloc];
}

@end

基本上我能够编译代码和调试,但是当CPVRTPFEffect类进行此调用时:

        if(pDelegate->PVRTPFXOnLoadTexture(pTexDesc->FileName, uiHandle, uiFlags) != PVR_SUCCESS)

我得到了EXC_BAD_ACCESS。我假设它没有找到我的回调方法,因为我设置了一个断点并且该行永远不会被调用。

这是我更新的代码,它使用delegate参数的bridge命令调用CPVRTPFXEffect :: Load。

    if(m_pEffect->Load(*m_pEffectParser, "Effect", c_szPfxFile,(__bridge myCppDelegate*)opaqueCppWrap, uiUnknownUniforms, &error) != PVR_SUCCESS)

感谢您的帮助!

更新2:项目使用ARC。这是我的viewController接口的样子:

@interface ViewController : GLKViewController {
    ...
    RNWrap* opaqueCppWrap;
    ...
}

@property (strong) RNWrap *opaqueCppWrap;

添加@property对EXC_BAD_ACCESS没有帮助。当我跟踪CPP代码时,我不确定如何“看到”pDelegate的值。当我将鼠标悬停在变量上时,Xcode不会显示任何内容。

我在CPVRTPFXEffect :: Load方法中添加了以下代码行(就在它崩溃的行之前):

        *pReturnError += PVRTStringFromFormattedStr("Here is your class typeid: %s.\n", typeid(pDelegate).name());
        return PVR_FAIL;

这是调试输出窗口中显示的内容:

这是你的班级类型:P21PVRTPFXEffectDelegate。

我不确定“P21”是什么意思(如果有的话),但看起来我已接近完成这项工作。我不知道,也许这就像它得到的一样接近。仍然崩溃,没有找到我的方法。

2 个答案:

答案 0 :(得分:0)

首先,您可能需要查看last article in the series on wrapping C++。其中大部分内容在最新版本的clang中变得更加简单。您可能不再需要此代码的一半。 ObjC ++对象现在可以拥有私有C ++属性而不需要任何技巧,同时保持纯粹的ObjC接口。

以下是您想要思考此问题的方法:

  • 构建作为委托的C ++对象。在C ++中编写设置委托等所涉及的所有代码。所以当它说“传递一个this指针”时,你应该传递一个this指针(因为你应该在C ++代码中这样做)。您在C ++调用中进行_bridge强制转换的事实是一个真正的提示,这是错误的。
  • 让ObjC拥有C ++对象作为属性。
  • 在C ++对象中编写C ++中的委托回调。如果有用,您可以让C ++对象根据需要调用ObjC对象,但如果C ++对象完成所有委托工作可能会更容易。

答案 1 :(得分:0)

我终于有了这个工作,但是为了这样做,我不得不从我的viewController中删除obj-c包装器类。这是代码的样子:

ViewController.h

struct Opaque;

@interface ViewController : GLKViewController {

    ...
    //RNWrap* opaqueCppWrap;  // this didn't work 
    struct Opaque *opaqueCpp; // try this
    ...
}

ViewController.mm

// declare the Opaque structure
struct Opaque {
public:
    Opaque() : cppobject() {};

    myCppDelegate cppobject;
};

viewDidLoad中

    // ... create opaque member on initialization
    opaqueCpp = new Opaque();

    //opaqueCppWrap = [[RNWrap alloc] init];  // old way of doing things using wrapper

将委托传递给Load方法

// old way using bridge cast and wrapper 
//if(m_pEffect->Load(*m_pEffectParser, "Effect", c_szPfxFile,(__bridge myCppDelegate*)opaqueCppWrap, uiUnknownUniforms, &error) != PVR_SUCCESS)

// this works...
if(m_pEffect->Load(*m_pEffectParser, "Effect", c_szPfxFile, (myCppDelegate*)opaqueCpp, uiUnknownUniforms, &error) != PVR_SUCCESS)

不确定为什么封装类不起作用,但我很高兴我的回调正常工作(appy no crashy!)

P,这很粗糙。有什么想法/评论吗?