简体   繁体   English

在运行时检查Swift中第三方框架中的弱链接符号

[英]Checking at runtime for weakly linked symbols from third-party framework in Swift

On macOS, I use an external framework (written in C) that must be installed by the user. 在macOS上,我使用必须由用户安装的外部框架(用C编写)。 In Swift, I need to check at runtime if it exists, and I can't use #available() since it is for OS-related features, and I am trying to track down an external framework. 在Swift中,我需要在运行时检查它是否存在,并且我不能使用#available(),因为它是与OS相关的功能,我试图追踪外部框架。 Also, NSClassFromString() is not useful since it is not an Objective-C framework. 此外,NSClassFromString()没有用,因为它不是Objective-C框架。

I have been trying to understand how to replicate the Objective-C equivalent for checking for a weakly-linked symbol such as: 我一直试图理解如何复制Objective-C等价物以检查弱链接符号,例如:

if ( anExternalFunction == NULL ) {
    // fail graciously
} else {
    // do my thing
}

but in Swift, this does not seem to work: the compiler states that since anExternalFunction is not optional, I will always get != nil, which make "Swift sense" but does not help me one bit. 但是在Swift中,这似乎不起作用:编译器声明由于anExternalFunction不是可选的,我总是得到!= nil,这使得“Swift sense”但是对我没有帮助。

I have found two solutions, but they stink up my code like you wouldn't believe: 我找到了两个解决方案,但他们发现我的代码就像你不相信一样:

Option 1, create an Objective-C file with a function called isFrameworkAvailable() doing the work, and calling from Swift 选项1,使用名为isFrameworkAvailable()的函数创建一个Objective-C文件,并执行该工作,并从Swift调用

Option 2, actually checking for the library with the following Swift code: 选项2,实际使用以下Swift代码检查库:

let libHandle = dlopen("/Library/Frameworks/TheLib.framework/TheLib", RTLD_NOW)

if (libHandle != nil) {
    if dlsym(libHandle, "anExternalFunction") != nil {
        return true
    }
}
return false

I have been unable to get Option 2 to work nicely with RTLD_DEFAULT since for some reason, it is defined in dlfcn.h (-2) but does not seem to be imported in Swift (like all negative pointers in that header: RTLD_NEXT, RTLD_DEFAULT, RTLD_SELF, RTLD_MAIN_ONLY). 我一直无法使选项2与RTLD_DEFAULT很好地协同工作,因为出于某种原因,它在dlfcn.h(-2)中定义但似乎没有在Swift中导入(就像该标题中的所有负指针一样:RTLD_NEXT,RTLD_DEFAULT ,RTLD_SELF,RTLD_MAIN_ONLY)。 I have found this ugliest hack to make it work: 我发现这个最丑陋的黑客让它工作:

if dlsym(unsafeBitCast(-2, to: UnsafeMutableRawPointer.self), "anExternalFunction") != nil {
    // library installed
}

So for option 2, I require the path or a hack, which I find particularly ugly (but it works) and Option 1 is not very "Swifty" and makes little sense to me: what is the proper way of doing this in Swift? 因此,对于选项2,我需要路径或黑客,我发现它特别难看(但它有效)而且选项1不是非常“Swifty”并且对我来说没什么意义:在Swift中这样做的正确方法是什么?

Edits: clarified question, explained Option 2 better. 编辑:澄清问题,更好地解释选项2。

I've found two ways of doing this: 我发现了两种方法:

    1. 1。
if let _ = dlopen("/Library/Frameworks/MyLibrary.framework/MyLibrary", RTLD_NOW) {
  print("Can open my library")
}
    2. 2。
#if canImport(MyLibrary)
  print("Can import my library")
#endif

The second seems clearly better from just a readability and type safety standpoint but I'm not sure what the tradeoffs are between the two. 从可读性和类型安全的角度来看,第二个似乎明显更好,但我不确定两者之间的权衡取舍。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何将第三方框架导入到我的Swift项目中? - How to import a third-party framework into my Swift project? Linux上的Swift-导入第三方模块 - Swift on Linux - importing third-party modules 第三方键盘中的resignFirstResponder() - resignFirstResponder() in Third-Party Keyboards 无法连接来自第三方库的代码 - Unable to connect code from a third-party library 使用第三方静态框架作为单个框架构建Swift动态框架 - Build Swift dynamic framework with third party static framework as a single framework 尝试根据第三方框架构建基于Swift的命令行工具时发生错误:此目标可能包含其自己的产品 - Build error while trying to build a Swift-based command line tool depending on a third-party framework: this target might include its own product XCode 不排除弱链接/可选框架 - XCode weakly-linked/optional framework not excluded 如何在没有任何第三方库的情况下在Swift 3.0中使用Alamofire解析JSON - How to parse JSON using Alamofire in Swift 3.0 without any third-party library Swift - 将第三方类型与我自己的协议一致,并且要求相互冲突 - Swift - Conform third-party type to my own protocol with conflicting requirement 如何在Swift 3中将十六进制转换为十进制? (无需第三方库和基金会的自写代码) - How to convert Hex to decimal in Swift 3? (self written code without third-party library and Foundation)
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM