【发布时间】:2017-11-14 04:42:07
【问题描述】:
在 macOS 上,我使用必须由用户安装的外部框架(用 C 编写)。在 Swift 中,我需要在运行时检查它是否存在,并且我不能使用 #available() 因为它用于与操作系统相关的功能,并且我正在尝试追踪外部框架。此外,NSClassFromString() 也没有用,因为它不是 Objective-C 框架。
我一直在尝试了解如何复制 Objective-C 等效项以检查弱链接符号,例如:
if ( anExternalFunction == NULL ) {
// fail graciously
} else {
// do my thing
}
但在 Swift 中,这似乎不起作用:编译器指出,由于 anExternalFunction 不是可选的,我将始终得到 != nil,这使“Swift 有意义”但对我没有一点帮助。
我找到了两种解决方案,但它们让我的代码变得很臭,就像你不会相信的那样:
选项 1,使用名为 isFrameworkAvailable() 的函数创建一个 Objective-C 文件,并从 Swift 调用
选项 2,实际使用以下 Swift 代码检查库:
let libHandle = dlopen("/Library/Frameworks/TheLib.framework/TheLib", RTLD_NOW)
if (libHandle != nil) {
if dlsym(libHandle, "anExternalFunction") != nil {
return true
}
}
return false
我无法让选项 2 与 RTLD_DEFAULT 很好地配合使用,因为由于某种原因,它在 dlfcn.h (-2) 中定义,但似乎没有在 Swift 中导入(就像该标头中的所有负指针一样: RTLD_NEXT、RTLD_DEFAULT、RTLD_SELF、RTLD_MAIN_ONLY)。我发现这个最丑陋的黑客使它起作用:
if dlsym(unsafeBitCast(-2, to: UnsafeMutableRawPointer.self), "anExternalFunction") != nil {
// library installed
}
所以对于选项 2,我需要路径或 hack,我觉得它特别难看(但它有效),选项 1 不是很“迅速”,对我来说没有什么意义:什么是正确的做法在斯威夫特?
编辑:澄清问题,更好地解释选项 2。
【问题讨论】:
-
不,不是因为我使用的第三方框架不是Objective-C框架,它是一个纯C库。 (更新问题)
-
这看起来相关(重复?)Check existence of global function in Swift
-
它很有用,但我不会称它为重复:答案来自 2016 年(这意味着不是 Swift 4),它的上下文略有不同,我没有找到它-询问前的长期调查。此外,带有 RTLD_SELF 的解决方案无法编译(未定义)。 Swift 4 中可能存在新的解决方案。
-
像
#define RTLD_DEFAULT ((void *) -2这样的 C 宏不会导入 Swift,但if dlsym(UnsafeMutableRawPointer(bitPattern: -2), "anExternalFunction") ...会不那么难看。 – 比较forums.developer.apple.com/thread/18816。
标签: swift dll frameworks dlsym weak-linking