如何在没有在.h文件中对其进行原型设计的情况下将Objective-C ++类暴露给swift

时间:2016-03-25 15:16:38

标签: c++ ios objective-c swift

我试图在我的Swift项目中使用C ++库,直到现在,它运行正常,只是当我尝试包含一个包含C ++代码的.h时,我遇到了一些问题。我的一个Objective-C ++ .h文件的.h。

以下是图片中的情况:

.h file

这是我的Objective-C ++类的.h。如您所见,init方法接受参数a SuperpoweredAdvancedAudioPlayerCallback,此类型在文件SuperpoweredAdvancedAudioPlayer.h中声明,该文件是用C ++编写的lib文件,因此我将其包含在内。

但问题是除了.mm文件外我不能包含C ++代码,否则,Xcode不会编译并说:

Error message

因此,我尝试将@interface块中的所有#import "SuperpoweredAdvancedAudioPlayer.h"块和SuperpoweredAdvancedAudioPlayerWrapped.h文件移到我的.mm文件中,但是我的SuperpoweredAdvancedAudioPlayerWrapped不会暴露给我Swift文件,逻辑,SuperpoweredAdvancedAudioPlayerWrapped.h文件(我包含在文件Bridging-Header中)现在是空的。

如果我只在我的.mm文件中移动#import "SuperpoweredAdvancedAudioPlayer.h",Xcode将无法编译并说SuperpoweredAdvancedAudioPlayerCallback不是类型,逻辑也是......

所以我坚持这一点,因为我不是Objective-C ++专家。

有什么想法解决这个问题吗?

1 个答案:

答案 0 :(得分:1)

问题是C ++类型(例如SuperpoweredAdvancedAudioPlayer)不能暴露给Objective-C或Swift,而只能暴露给Objective-C ++。因此,你的包装器,因为它使用C ++类,需要在Objective-C ++中实现。包装器的头(即.h文件)不应引用任何C ++代码。

我在Superpowered附带的示例中看到了一些回调用法,它们通常在Objective-C ++(。mm)文件中实现回调。您可以自己搜索代码,因为社区查看特定于产品的示例不会提供非常丰富的信息。

在这种情况下我可能会做什么

  • 不包含SuperpoweredAdvancedAudioPlayer.h标题 声明SuperpoweredAdvancedAudioPlayerWrapped的标头 接口
  • 根据自定义数据类型在..Wrapped.h中表达界面 这将在.mm文件中实现,以及C ++代码所在的文件 将被引用。

例如,您可以引入一个SuperpoweredAdvancedAudioPlayerCallbackWrapped类型,该类型将传递给..Wrapped init方法。

以下是如何完成这样的事情的模拟示例。首先,这是我们想要从Swift(mylib.cpp)调用的一些C ++代码:

#include "mylib.hpp"

MyCpp::MyCpp(MyCppCallback cb, int i) : m_CB(cb), m_Int(i) {}

int MyCpp::f(int i)
{
    return m_CB(i + m_Int);
} 

和相应的头文件(mylib.hpp):

#ifndef mylib_hpp
#define mylib_hpp

/**
 * Callback type used by the C++ code.
 */
typedef int (*MyCppCallback) (int);

/**
 * A simple C++ class.  
 */
class MyCpp
{
public:
    MyCpp(MyCppCallback, int);
    int f(int);
private:
    MyCppCallback m_CB;
    int m_Int;
};

#endif /* mylib_hpp */

标头mylib.hpp不能直接或间接包含在Swift桥接头中,因此我们需要一个包装器。顺便说一句,扩展名可能是.h而不是.hpp,它并不重要。

包装器代码必须是Objective-C ++,因为它使用C ++类型(MyCpp),这里是(wrapper.mm):

#import "mylib.hpp"
#import "wrapper.h"

@implementation MyWrapper
{
    MyCpp * pMyCpp;
}

-(id)init: (wrapper_cb_t)cb withInt: (int)i
{
    pMyCpp = new MyCpp( cb, i );
    return self;
}

-(int)f: (int)i
{
    return pMyCpp->f(i);
}

@end

这里是相应的标题wrapper.h,它可以包含在Swift桥接头中,因为它没有任何C ++内容:

#ifndef wrapper_h
#define wrapper_h

#import <Foundation/Foundation.h>

/**
 * Here we just repeat the callback typedef from mylib.hpp.  We can do this because
 * it does not depend on C++ types.  If it did, we could come up with some
 * "glue" code in wrapper.mm.
 */
typedef int (*wrapper_cb_t) (int);

/**
 * This is the wrapper interface.  It doesn't depend on any C++ types.
 */
@interface MyWrapper : NSObject

-(id)init: (wrapper_cb_t)cb withInt: (int)i;
-(int)f: (int)i;

@end

#endif /* wrapper_h */

桥接标题如下所示:

#import "wrapper.h"

以下是通过包装器使用C ++代码的示例Swift代码:

/**
 * This is a Swift callback function of type wrapper_cb_t.
 * To figure out how the wrapper's signature is imported into Swift,
 * just type "wrapper_cb_t" somewhere in the code, click on it, and
 * Xcode Quick Help should show you the signature.
 */
func swift_cb(i: Int32) -> Int32
{
    return i + 111
}

/**
 * Now create an instance of MyWrapper...
 */
let w : MyWrapper = MyWrapper(swift_cb, withInt: 3)

/**
 * ... and use it:
 */
print("f() in the wrapper returned \(w.f(4))")

此示例是一段非常简化的代码,并不代表生产质量。例如,不包括内存管理。

请注意,一旦开始处理回调,事情变得比让Swift调用Objective-C / C ++代码复杂得多。现在你必须编写将由C和/或C ++调用的代码。如果你搜索&#34; Swift回调c&#34;你会发现很多有趣的信息。在这个论坛或谷歌。