如何在Swift项目中使用Superpowered库

12

我想用Swift创建一个简单的应用程序,通过iPhone的麦克风录制声音,然后播放录制的声音。

为此,我想使用Superpowered库,它是一个具有头文件的静态库。

因此,我尝试将.a和.h文件拖放到我的项目中(Xcode会为我创建桥接头文件),将.a添加到“Linked Frameworks and Libraries”中,在Xcode > Target > General中(也在Xcode > Target > Build phases > “Link Binary With Libraries”中),并在Xcode > Target > Build Settings > Search Paths > Library Search Paths中索引.h文件路径。

但是,我遇到了“ld: symbol(s) not found for architecture arm64”的错误,与这里完全相同,并尝试了在网上找到的所有解决方法,仍无法编译。

因此!

Superpowered为我们提供了一个示例应用程序,以显示如何混合Objective-C++并在Swift项目中使用其库(如果您想要链接,请参见这里)。

以下是示例项目的一些截图,其中包含我的理解和不理解的内容:

Bridging header file Superpowered

桥接头文件包含了我想在Swift代码中使用的库方法的原型(虽然我不喜欢这样,但如果这是唯一的方式…)。

ViewController文件

这是Swift代码所在的viewController文件,我可以通过Bridging-Header-File创建一个Superpowered对象,并调用其中的方法。

.mm文件

但是我甚至不知道为什么有这个Objective-C++文件以及它包含了什么内容。它好像出现得很突然,甚至没有他们的库文件。

有了这个示例项目的想法,我创建了自己的项目,以下是一些截屏:

Bridging-Header-File

与示例项目中相同的Bridging-Header-File,只是我包含了SuperpoweredIOSAudioIO.h,这样我就可以使用SuperpoweredIOSAudioIODelegate

viewController

这是我的viewController文件,其中包含Swift代码,我可以通过Bridging-Header-File创建一个Superpowered对象,并调用其中的方法。

到这里为止一切都很好,但是我无法创建SuperpoweredRecorder对象。如果我尝试在我的Bridging-Header-File中包含SuperpoweredRecorder.h文件,就会出现这些错误:

错误

我发现原因是因为SuperpoweredRecorder.h包含一些.cpp文件,我需要创建一个cpp的包装器(有点像我之前用的桥接头文件,对吧?),但是那个包装器还要包括一个.h文件和一个.mm文件,我不知道在那个.mm文件里应该放什么(SuperpoweredRecorder.cpp的代码?但我无法访问它)。

所以,我对所有这些东西有点困惑,您能帮我理解如何在我的Swift项目中使用所有的Superpowered库吗?

3个回答

7

如我在对@OmniProg的评论中所说,我与Superpowered的CTO进行了一次小谈话,这帮助我找到了以下解决方案。

因此,由于Swift不能直接与C++交互,但可以与Objective-C交互,我不得不在Objective-C++(.mm文件,介于C++和Objective-C之间的混合文件)中创建对象,以包装Superpowered库的C++类。

以下是使用库中的SuperpoweredRecorder对象的示例:

SuperpoweredRecorderWrapped.h

这里我创建了一个名为SuperpoweredRecorderWrapped的.h文件,其中原型化了我的包装器,并且在其中也原型化了我想要使用的库中所有SuperpoweredRecorder的方法。

SuperpoweredRecorderWrapped.mm

然后我创建了一个新的.m文件,将其重命名为.mm,并在其中实现了SuperpoweredRecorderWrapped。我导入了SuperpoweredRecorderWrapped.hSuperpoweredRecorder.h两个文件。我创建了一个SuperpoweredRecorder对象作为属性,命名为_wrapped,并在我的方法中调用_wrapped对象的相应方法。这样,当我在Swift代码中调用SuperpoweredRecorderWrappedstart方法时,它将调用_wrappedstart方法,即一个SuperpoweredRecorder对象。看到这个技巧了吗?

Bridge-Header

最后,我将所有包装类都包含在我的Bridging-Header中,这样我就可以从Swift中实例化我的包装对象。
注意:所有的C++代码必须在.mm文件中,所以我将包含C++代码的.h文件的#include放在我的.mm文件中而不是.h文件中。

我正在使用类似的技巧来包装C++,但问题是找不到一些依赖项,例如: Undefined symbols for architecture x86_64: "_AVURLAssetPreferPreciseDurationAndTimingKey", referenced from: __ZL9makeAssetPKcb in libSuperpoweredAudioOSX.a(ipodreader.o)详细信息请查看此问题: https://github.com/superpoweredSDK/Low-Latency-Android-iOS-Linux-Windows-tvOS-macOS-Interactive-Audio-Platform/issues/481 - PerfectlyRock
嗨@YoanGJ,我在将SuperpoweredFrequencyDomain集成到Swift项目中时需要您的帮助... - Ahtazaz
嗨@Mr.Ahtazaz,我已经好几年没用过这个库了,所以不确定能否帮到你,但我会尝试...告诉我吧。 - YoanGJ
感谢您的回复,YoanGJ。我已经成功集成了它,但在实现SuperPoweredEcho时需要帮助。 - Ahtazaz
你能给我你的邮件@YoanGJ吗? - Ahtazaz
我已经给你发送了一条消息。@YoanGJ - Ahtazaz

3
我没有使用过Objective-C++编程,但我有C、C++、Objective-C和Swift方面的经验,因此根据查看Superpowered SDK和示例代码得出了一些观察和想法。
桥接头文件可以让Swift直接与Objective-C进行接口交互,由于Objective-C是C的一个严格超集,这意味着也可以与C进行接口交互。然而,您不能直接与C++进行接口交互,这就是Objective-C++派上用场的地方。从我所看到的,您可以在Objective-C++中混合使用Objective-C和C++代码,这允许Objective-C使用C++类。
现在进入一些具体内容。
您查看的SuperpoweredFrequencies示例中的桥接头文件引入了一个新的Objective-C类Superpowered,它不是库的一部分,而是示例的一部分,并在Superpowered.mm中实现。这是一个Objective-C++文件,因为Superpowered调用了一些C++代码。
查看Superpowered.mm,您会发现它导入了Objective-C头文件:
#import "SuperpoweredFrequencies-Bridging-Header.h"
#import "SuperpoweredIOSAudioIO.h"

还有C和C++头文件:

#include "SuperpoweredBandpassFilterbank.h"
#include "SuperpoweredSimple.h"

我们也可以在C++代码中使用import代替include,但他们可能只是想强调这是C++代码。看一下SuperpoweredBandpassFilterbank.h,我们可以看到SuperpoweredBandpassFilterbank是一个C++类。它在Superpowered.mm中被Superpowered Objective-C++类使用,查看filters成员,它是指向SuperpoweredBandpassFilterbank对象的指针。
在你尝试构建的项目中,我看到Superpowered接口在桥接头文件中声明,但我没有看到实现。无法导入SuperpoweredRecorder.h是由于SuperpoweredRecorder.h是一个C++头文件。 #include应该在你的Objective-C++(.mm)文件中,因为Swift无法理解C++,所以在桥接头文件中是无用的。
希望这有所帮助。欢迎来到C++的世界。

1
经过一段时间和与Superpowered的CTO的一些交谈,我已经理解了你在这里解释的所有内容,并且我已经找到了解决方案,我将在几分钟内发布。但现在事情已经很清楚了,谢谢! - YoanGJ

0

我有点惊讶,你竟然需要提供方法的原型。我以前在我的 Swift 项目中使用过 Objective C 库,只需要在桥接头文件中添加头文件。

以下是我项目中的一个示例。桥接头文件只包含这些内容:

//  Use this file to import your target's public headers that you would like to expose to Swift.
//

#import "QTouchposeApplication.h"
#import <FBSDKCoreKit/FBSDKCoreKit.h>
#import <FBSDKLoginKit/FBSDKLoginKit.h>
#import <VungleSDK/VungleSDK.h>

是的,当我使用Objective-C库时也没有问题,但是这里的库是用C++编写的,这使得设置更加痛苦。 - YoanGJ
你说得对,我没有从你的原始帖子中理解到这一点,但是看了@OmniProg的答案,现在明白了。感谢您发布您的解决方案! - I'm stuck

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接