iOS Objective-C 应用程序可以使用嵌套静态 ObjC/Swift 库吗?

Can iOS Objective-C app use nested static ObjC/Swift libs?

仅限 OBJ-C...

也就是说, ObjC 应用程序导入 ObjC 静态库 A。 静态库 A 导入静态库 B。 静态库 A 具有调用库 B 中的函数的函数。 应用程序只调用库A中的函数,不调用库B中的函数。

我可以假设库 A 或 B 可以是 Obj-C 或 Swift 吗? IE。一个 ObjC 应用程序可以导入一个 ObjC-or-Swift 静态库 A 本身导入第二个 ObjC-or-Swift 静态库 B 吗? (是的,4 个用例排列)

只要库导出 Objective-C 兼容符号,它们是用 Objective-C、Swift、C++ 或任何其他编译的都没有关系语言。

而且我们知道 Swift 编译器为所有标有 @objc(显式或隐式)的声明导出 Objective-C 兼容符号。

从消费者的角度来看,使用哪种语言生成库并不重要,只要 Objective-C compiler/linker 可以使用这些库导出的符号即可。

我为您创建的 git 存储库 https://github.com/CombineCppSwiftObjcInStaticLib 显示了这个..

您在 BLE_central.swift 中的初始 @objc func run_central() 被公开,这会触发预编译器生成 objc 兼容的 headers(桥),然后再次可以从导入此生成的 header 时 .mm(objc++) 或 .m(objc) 中的方法。

事实上 Hub_lib 在 repo 中是一个混合了 Swift 的静态 ObjC++ 库。反之亦然。 header 是这里成功的关键。 如果你可以提供一些 objc 或 c 或 c++ header 到 swift 功能它变得兼容和明智的相反。我的意思是,总的来说,这就是 header 的想法。如果你没有 headers,那并不意味着你不能调用一些外部的东西,这只是意味着你会称之为盲目的。一个合适的 IDE 会在你尝试做这些邪恶的事情之前抱怨,未知的入口点也就是未知的符号等等。所以你选择一个合适的 header - always.

要将 swift 与其他语言正确结合,很高兴知道总是有两种桥接方式。

在 Objective-C 的情况下(以及 Objective-C++)它是

  1. 桥接 Swift (projectname-Bridging-Header.h),
  2. 和 Swift 的桥接(用 @objc 公开触发自动内部生成 projectname-Swift.h 文件。所以这个 header 在文件浏览器中是“不可见的”在左侧。你也不会在 repo 中找到它作为文件,它由 modulename 命名,即 project-name)。最后提到的header你甚至可以自己手动写,有很多麻烦back-draws。

提示:可执行代码是可执行代码。不管是什么语言,只要它是为正确的设备架构编译的,并且有调用的符号,你就知道如何处理数据 returned.

另一个提示:有一种方法可以处理 swift see docu 中的 C 指针,它变成 swift 数据类型,您可以使用它来另辟蹊径并将函数声明为 return 那些来自 swift.

并且在Swift中直接使用C也是可以的。编译器考虑如果你显式标记一些代码为C。 extern "C" { /* code */ } 会导致C++编译器记住,这仍然是C++代码以这种方式编译函数,它可以从C调用 (和 Swift)

//Example.hpp //no target membership
#ifdef __cplusplus
#include <stdio.h>
class Example {
private:
    const char * _name;
public:
    Example(const char *name);
    ~Example(void);
    int getLen(void);
};
#endif

应该有一个 Example.cpp 并且不要忘记告诉 Xcode 你处理 c++
#ifdef __cplusplus + #endif

//Example.cpp //has target membership
#include "Example.hpp"
#ifdef __cplusplus 
#include <stdio.h>
#include <string>
//code implementation according to example.hpp
Example::Example(const char *name) {
    _name = name;
}
int Example::getLen() {
    return (int)strlen(_name);
}
#endif
//ExampleWrapper.cpp //has target membership
#include "Example.hpp" //c++ header file

extern "C" int myCppFunction(const char *s) 
{
    // Create an instance of Example, defined in the library
    // and call getLen() on it, return result.
    return Example(s).getLen();
}

所以这个函数需要在桥接中声明header才能使用它。

//
//  Use this file to import your target's public headers that you would like to expose to Swift.
//
// for extern "C" functions declare them one by one here
// as implemented in ExampleWrapper.cpp
// becomes "func myCppFunction(_ s: UnsafePointer<Int8>!) -> Int32" in swift
int myCppFunction(const char * s);

然后从swift调用..

os_log("The result from C++ is %u", myCppFunction("12345"))

所以事实上,是的。在 App 中集成调用静态库 B 的静态库 A 是可能的。只要您为每个需要知道其他库头部内容的部分提供一些 header,编译就会很愉快。这对应用程序来说是正确的,因为它对彼此下的库和框架也是正确的。

编辑 这里有一些重要的东西要阅读 Swift Package Manager C 支持 https://github.com/apple/swift-evolution/blob/master/proposals/0038-swiftpm-c-language-targets.md