【发布时间】:2014-07-25 10:02:35
【问题描述】:
我刚刚将我的 .m 文件更改为 .mm 并使用 C++。有没有办法用 Swift 做同样的事情?
【问题讨论】:
标签: c++ objective-c swift
我刚刚将我的 .m 文件更改为 .mm 并使用 C++。有没有办法用 Swift 做同样的事情?
【问题讨论】:
标签: c++ objective-c swift
一个(许多)技巧是
您不能像往常一样将@interface 和@implementation 放在同一个.mm 文件中。
所以在你的桥接头文件中有
#import "Linkage.hpp"
Linkage.hpp 具有 Linkage 的 @interface,Linkage.mm 具有 .mm 的 @implementation
然后
您只将#include "yourCpp.hpp" 放在 Linkage.mm 文件中,没有放在 Linkage.hpp 文件中。
在许多在线示例/教程中,作者只是将@interface 和@implementation 放在同一个.mm 文件中,就像人们经常做的那样。
这适用于非常简单的 cpp 桥接示例,但是,
问题是:
如果你的 yourCpp.hpp 有任何它肯定会的 c++ 特性(比如第一行 #include <something>),那么这个过程将会失败。
但如果您只是没有在 Linkage header 文件中有 #include "yourCpp.hpp"(它是可以将它放在 .mm 文件中,显然你需要这样做)——它可以工作。
不幸的是,这只是整个过程中的一个提示。
【讨论】:
其他答案略有不准确。实际上,您可以在同一个文件中混合使用 Swift 和 [Objective-]C[++],尽管这与您期望的不太一样。
此文件 (c.swift) 编译为具有 swiftc c.swift 和 clang -x objective-c c.swift 的有效可执行文件
/* /* */
#if 0
// */
import Foundation
print("Hello from Swift!")
/* /* */
#endif
#include <stdio.h>
int main()
{
puts("Hello from C!");
return 0;
}
// */
【讨论】:
混淆可能来自这样的假设,即只需将文件扩展名从 .m 更改为 .mm 即可桥接这些语言,而实际上,它并没有做任何此类事情。与.cpp 产生摩擦的不是.mm,而是.h 标头绝对不能是C++ 标头。
在同一个项目中,可以愉快地混合C、C++、Objective-C、Objective C++、Swift,甚至是Assembly。
...Bridging-Header.h:你使用这个桥将 C、Objective-C 和 Objective-C++ 暴露给 Swift李>
<ProductModuleName>-Swift.h:自动向 Objective-C 公开标有 @objc 的 Swift 类
.h:这是棘手的部分,因为它们被模糊地用于所有风格的 C、++ 与否、Objective 与否.当.h 不包含单个C++ 关键字时,例如class,可以将其添加到...Bridging-Header.h,并公开对应.c 的任何函数或 .cpp 它声明的功能。否则,该标头必须包含在纯 C 或 Objective-C API 中。
在同一个文件中,不能全部混合 5.在同一个源文件中:
.swift:你不能把 Swift 和任何东西混在一起.m:您可以将 Objective-C 与 C 混合使用。 (@Vinzzz).mm:您可以将 Objective-C 与 C++ 混合使用。这座桥是Objective-C++。 (@Vinzzz)。.c: 纯 C
.cpp:你可以混合使用 C++ 和 Assembly (@Vality).h:无处不在且模棱两可的C、C++、Objective-C或Objective-C++,所以答案这取决于。
参考文献
【讨论】:
我在官方资源中提供了指向SE-0038 的链接,描述为 这维护了对 Swift 编程语言的更改和用户可见增强的建议。
截至今天的状态是,这是已被接受但尚未安排的功能请求。
此链接旨在引导任何寻找此功能的人朝着正确的方向前进
【讨论】:
没有。当您从 .m 切换到 .mm 时,您实际上是从 Objective-C 切换到另一种语言(有许多细微差别),称为 Objective-C++。所以你并没有真正使用 C++;您正在使用接受大多数 C++ 作为输入的 Objective-C++(与 C++ 接受大多数但不是所有 C 作为输入的方式相同)。当我说它不完全是 C++ 时,请考虑一个包含名为 nil 的变量的 C++ 文件(这是合法的 C++),然后尝试将其编译为 Objective-C++。
Swift 没有相同的关系。它不是 C 或 C++ 的超集,您不能直接在 .swift 文件中使用。
"Using Swift with Cocoa and Objective-C" 也告诉我们:
您不能将 C++ 代码直接导入 Swift。相反,为 C++ 代码创建一个 Objective-C 或 C 包装器。
【讨论】:
.mm 您的文件并(几乎)完成。 Swift 并非如此。
nil的变量,比如int nil
如果这对任何人都有帮助,我还有一个简短的教程,关于从一个简单的 Swift 命令行实用程序调用一个简单的 C++ 静态库。这是一段非常简单的概念验证代码。
不涉及 Objective-C,只涉及 Swift 和 C++。 C++ 库中的代码由 C++ 包装器调用,该包装器实现具有外部“C”链接的函数。然后在桥接头中引用该函数并从 Swift 中调用。
【讨论】:
您也可以跳过 Objective-C 文件。只需添加一个带有 .cpp 源文件的 C 头文件。头文件中只有 C 声明,并在源文件中包含任何 C++ 代码。然后在**-Bridging-Header.h中包含C头文件。
以下示例返回一个指向 C++ 对象 (struct Foo) 的指针,因此 Swift 可以存储在 COpaquePointer 中,而不是在全局空间中定义 struct Foo。
Foo.h 文件(Swift 可以看到 - 包含在桥接文件中)
#ifndef FOO_H
#define FOO_H
// Strictly C code here.
// 'struct Foo' is opaque (the compiler has no info about it except that
// it's a struct we store addresses (pointers) to it.
struct Foo* foo_create();
void foo_destroy(struct Foo* foo);
#endif
内部源文件 Foo.cpp(Swift 看不到):
extern "C"
{
#include "Foo.h"
}
#include <vector>
using namespace std;
// C++ code is fine here. Can add methods, constructors, destructors, C++ data members, etc.
struct Foo
{
vector<int> data;
};
struct Foo* foo_create()
{
return new Foo;
}
void foo_destroy(struct Foo* foo)
{
delete foo;
}
【讨论】:
extern "C" 将标头包装在包含的位置,而不是 #ifdef'ed 在标头文件本身中。太棒了!
不,不在单个文件中。
但是,您可以在 Swift 项目中使用 C++,而无需静态库或框架。就像其他人所说的那样,关键是制作一个 Objective-C 桥接头标头,其中 #includes C 兼容的 C++ 标头标记为与 extern "C" {} 技巧兼容的 C。
【讨论】:
我还有一个快速结合opencv的演示程序。
您可以从https://github.com/russj/swift_opencv3_demo下载。
有关演示的更多信息http://flopalm.com/opencv-with-swift/。
【讨论】:
这是我尝试使用 clang 工具来自动化 C++/swift 通信。您可以从 swift 中实例化 C++ 类,从 C++ 类继承,甚至可以在 swift 中覆盖虚拟方法。
它将解析您要导出的 C++ 类,并自动生成 Objective-C/Objective-C++ 桥。
【讨论】:
我编写了一个简单的 Xcode 6 项目,展示了如何混合 C++、Objective C 和 Swift 代码:
https://github.com/romitagl/shared/tree/master/C-ObjC-Swift/Performance_Console
特别是该示例从 Swift 调用了一个 Objective C 和一个 C++ 函数。
关键是创建一个共享头文件Project-Bridging-Header.h并将Objective C头文件放在那里。
请下载项目作为一个完整的例子。
【讨论】:
ObjCtoCPlusPlus.h/``.mm` 存在的唯一目的是为 C++ 代码提供 Ob-C 接口——它是桥梁,这是这里的必要组件。将包含保留在它们所在的位置,并在 ObjCtoCPlusPlus.… 文件中为您需要访问的每个 C++ 方法添加一个方法。你最好仔细阅读sourcemaking.com/design_patterns/adapter
我刚刚使用 Swift、Objective-C 和 C++ 制作了一个小示例项目。这是一个如何在 iOS 中使用 OpenCV 拼接的演示。 OpenCV API 是 C++,所以我们不能直接从 Swift 与它对话。我使用一个小的包装类,它的实现文件是 Objective-C++。 Header 文件是干净的 Objective-C 文件,因此 Swift 可以直接与之对话。您必须注意不要将任何 C++ 文件间接导入 Swift 与之交互的标头中。
【讨论】:
Swift 与 C++ 不直接兼容。您可以通过使用 Objective-C 包装 C++ 代码并在 Swift 中使用 Objective C 包装器来解决此问题。
【讨论】: