Swift 包和 `#if canImport(...)` 。它是如何工作的?

标签 swift conditional-compilation swift-package-manager

请原谅模糊的标题。

我正在尝试构建一个包来帮助我使用第三方云存储 API(例如 Firebase 存储),添加 Combine 支持等。这个包对 CloudKit 做同样的事情。一切都编译得很好,但是当我将包模块导入到我的一个单独的项目中时,该模块显然缺少一些公共(public)符号...

具体来说,那些包裹在 #if canImport(FirebaseStorage) 条件中的。由于 Firebase 尚不支持 SwiftPM,因此包的这一部分在包项目本身中的行为符合预期;它只是跳过了编译整个位。我认为可以导入此模块的客户端项目可以很好地编译它。

旁白:我正在尝试做的事情看起来像是可选的依赖项。我不想必须导入 Firebase 才能使用此包的其他功能。我考虑过将包拆分成单独的子包,每个子包取决于我要使用的特定第三方库。无论如何我可能会那样做。但问题仍然是 Firebase 尚不支持 SwiftPM ( although I hear they're close )。

我的问题类似于 this one .我的客户端项目似乎看不到条件符号,尽管它可以导入 FirebaseFirebaseStorage 就好了!我的意思是生成的模块 header 完全缺少它们,阻止我的客户端项目在我使用它们时进行编译。

在我看来,编译条件永远不会离开包自身的依赖目标范围。是这样吗?还是我错过了一些明显的东西?我一直认为 Swift Packages 只是将 Swift 源文件导入并编译为命名模块,但现在我认为并非如此。

有没有一种方法可以将代码构建到一个 Swift 包中,该包仅在客户端可以导入尚不支持 SwiftPM 的第三方模块时编译?还是条件编译不能那样工作?

编辑:Here is the Swift documentation关于条件编译,供引用。

最佳答案

(2020年4月的经验回答)

看来我只是误解了编译顺序。

导入我的打包模块(我们称它为 CloudStorage)会在客户端项目中声明对该模块的依赖关系。在客户端项目可以使用其其他依赖项进行编译之前,CloudStorage 需要在没有主项目依赖项的情况下进行编译。由于 CloudStorage 对这些依赖项一无所知,因此这些依赖项的 canImport 计算结果为 false。

这可能在 Swift 的更高版本中发生了变化。我还没有再试一次。

关于Swift 包和 `#if canImport(...)` 。它是如何工作的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61053928/

相关文章:

ios - 在 iOS 10+ 项目中导入具有 13.0 目标的社区 SwiftUI 包

ios - 从 cocoapods 过渡到 Swift Package Manager

swift - 如何在嵌入的 tableView 上实现编辑/删除行为?

ios - 通过 UIimageview 和 uiimagepicker 显示圆形图片

swift - Firebase 查询未被触发

条件编译#ifdef

ios - 在 StoryBoard 中显示图像而不是 UIBarButton 的文本

cocoa - 在禁用 GC 的情况下编译时是否有条件语句来排除代码?

c# - C# 中的条件编译 hackery - 有没有办法解决这个问题?

xcode - 从嵌套的 Swift 包访问 Assets 时,SwiftUI 预览会崩溃