我试图在我的Swift项目中使用C ++库,直到现在,它运行正常,只是当我尝试包含一个包含C ++代码的.h时,我遇到了一些问题。我的一个Objective-C ++ .h文件的.h。
以下是图片中的情况:
这是我的Objective-C ++类的.h。如您所见,init方法接受参数a SuperpoweredAdvancedAudioPlayerCallback
,此类型在文件SuperpoweredAdvancedAudioPlayer.h
中声明,该文件是用C ++编写的lib文件,因此我将其包含在内。
但问题是除了.mm文件外我不能包含C ++代码,否则,Xcode不会编译并说:
因此,我尝试将@interface
块中的所有#import "SuperpoweredAdvancedAudioPlayer.h"
块和SuperpoweredAdvancedAudioPlayerWrapped.h
文件移到我的.mm文件中,但是我的SuperpoweredAdvancedAudioPlayerWrapped
不会暴露给我Swift文件,逻辑,SuperpoweredAdvancedAudioPlayerWrapped.h
文件(我包含在文件Bridging-Header中)现在是空的。
如果我只在我的.mm文件中移动#import "SuperpoweredAdvancedAudioPlayer.h"
,Xcode将无法编译并说SuperpoweredAdvancedAudioPlayerCallback
不是类型,逻辑也是......
所以我坚持这一点,因为我不是Objective-C ++专家。
有什么想法解决这个问题吗?
答案 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;你会发现很多有趣的信息。在这个论坛或谷歌。