我如何为一个cpp类做一个objective-c委托



我一直在尝试将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_peeffect ->Load调用中将指针传递给这个cpp类。这看起来正确吗?

谢谢。

注:对不起,如果我的代码格式不好。我还在学习。

编辑:这是我发现的关于混合objective-c和cpp的例子。这似乎和我想做的很相似。

更新:这里有一些额外的信息(由user1118321请求)

需要委托的CPP类是CPVRTPFXEffect (PVRTPFXParserAPI.h -来自powerVR SDK 3.0)。我会添加一个链接,但我不确定这是否允许。这里有一个类头文件的链接,但是这个版本(以及网络上的其他版本)不包括load方法的pDelegate属性。我假设它们是以前版本的例子。请告诉我是否可以发布这个类文件,我会这样做的。

我发现了一个很好的例子,我认为我应该从阅读这个线程。这是目前为止的内容:

My CPP delegate class…

    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

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

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

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

这是我更新的代码调用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;

添加@属性对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"是什么意思(如果有的话),但看起来我接近这个工作。我不知道,也许这是最接近的了。

首先,您可能想看一下本系列关于包装c++的最后一篇文章。在最新版本的clang中,大部分都变得简单多了。您可能不再需要这些代码的一半了。objc++对象现在可以拥有私有的c++属性而不需要任何技巧,同时保持一个纯ObjC接口。

你应该这样思考这个问题:

    构建一个c++对象作为委托。用c++编写与设置委托等相关的所有代码。所以当它说"传递一个this指针"时,你应该传递一个this指针(因为你应该在c++代码中这样做)。你在c++调用中做_bridge强制转换的事实是一个真正的暗示,有些事情是错误的。
  • 让一个对象拥有c++对象作为属性。
  • 在c++对象中使用c++编写委托回调函数。如果有用的话,你可以让c++对象根据需要调用ObjC对象,但如果c++对象完成所有委托工作可能会更容易。

我终于得到了这个工作,但不得不从我的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)

不知道为什么包装器类不工作,但我很高兴我的回调正在工作(快乐没有崩溃!)

呸,那太糟糕了。有什么想法/评论?

相关内容

  • 没有找到相关文章

最新更新