storyboard - Swift 包管理器 - Storyboard包

标签 storyboard bundle swift-package-manager

我正在尝试在我们的一个具有 Storyboard的项目中添加对 SPM 的支持。

目前我们获取它 UIStoryboard(name: String, bundle: String?) 但这似乎不适用于 SPM,因为实际上并没有 bundle 。即使打印所有 bundle 也不会显示我们包裹的 bundle 。

我们有什么方法可以支持 Storyboard,或者 SPM 仅仅是文件吗?

尝试:

UIStoryboard(name: "GiftCards", bundle: Bundle(for: self))
UIStoryboard(name: "GiftCards", bundle: Bundle(for: type(of: self)))
UIStoryboard(name: "GiftCards", bundle: Bundle(identifier: "com.x.x"))

最佳答案

更新:XCode 14.2(也许更早)不需要以下任何步骤。包中的 Storyboard会根据需要自动加载。感谢 @derpoliuk 的回答指出了这一点并提供了 GitHub 示例。

从 Xcode 12.0 开始,这种方法可以工作,但需要一些额外的步骤才能完成。

场景:

  • 一个显示来自名为 BadgeKit 的包的嵌入式 Storyboard的应用
  • 名为 BadgeKit 的 Swift 包,带有 Package.swift header //swift-tools-version:5.3 或更高版本
  • BadgeKit 中名为 BadgeKit.storyboard 的 Storyboard

目标:

  • 在应用 Storyboard中添加 Storyboard引用并使其在应用中运行

步骤:

将 Storyboard 引用添加到应用 Storyboard 并进行如下配置:

Storyboard Reference property panel with Storyboard value "BadgeKit" and Bundle identifier "BadgeKit-BadgeKit-resources"

带有 Storyboard 值 BadgeKit 和 bundle 标识符 BadgeKit-BadgeKit-resources 的 Storyboard Reference 属性面板。

Xcode 自动生成一个包(及其标识符),以便您使用以下格式保存在 SPM 包中找到的资源:[包名称]-[包目标名称]-资源。在我们的例子中,包名称和目标名称是相同的 (BadgeKit)。

虽然 SPM 资源包始终在构建过程中创建并包含在应用程序中,但它们在运行时不会在包外部自动可用。如果您没有在代码中的任何位置导入和使用包的目标,Xcode 会尝试通过不加载该包的资源包来进行优化(这可能是 Apple 的一个疏忽,仅 Storyboard引用不足以触发此操作)。因此,如果您仅在 Storyboard 中使用 SPM 包的资源,则需要一种解决方法来诱骗 Xcode 使 SPM 包的 bundle 可用。

将此代码添加到应用的 AppDelegate.swift 文件中作为解决方法:

@UIApplicationMain final class AppDelegate: UIResponder {

    […]

    override init() {
        super.init()
        
        // WORKAROUND: Storyboards do not trigger the loading of resource bundles in Swift Packages.
        let bundleNames = ["BadgeKit_BadgeKit"]
        bundleNames.forEach { (bundleName) in
            guard
                let bundleURL = Bundle.main.url(forResource: bundleName, withExtension: "bundle"),
                let bundle = Bundle(url: bundleURL) else {
                preconditionFailure()
            }
            bundle.load()
        }

        […]
    }

    […]

}

在我们的示例中,数组 bundleNames 包含一个字符串,该字符串对应于我们的包将在构建过程中为其资源创建的 bundle 的预期文件名。 Xcode 自动命名这些包文件,如下所示:[包名称]_[包目标名称].bundle。请注意, bundle 的文件名与其标识符不同。

如果您想知道哪些包(及其相应的标识符)在运行时加载并可用,您可以使用以下代码进行故障排除:

let bundles = Bundle.allBundles
bundles.forEach { (bundle) in
    print("Bundle identifier loaded: \(bundle.bundleIdentifier)") }
}

在SPM BadgeKit包中配置 Storyboard:

  • 在“Module”中填写 SPM 包目标名称(“BadgeKit”)
  • 取消选中“从目标继承模块”

Storyboard property panel with Module value BadgeKit

关于storyboard - Swift 包管理器 - Storyboard包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58000140/

相关文章:

ios - 现代 Xcode 5 iOS7 项目中创建的 UIWindow 在哪里?

macos - 无法加载一个或多个 i18n 程序集

Android ListFragment 不在 onSaveInstanceState() 中保存包/不在 onActivityCreated() 中检索包

ios - 包产品 'MyLibrary' 不能用作此目标的依赖项,因为它使用了不安全的构建标志

iphone - 带 Storyboard 的 UITabBar 图像到 UITabBarItem

ios - Storyboard中 View Controller 外部的 UIView

php - 如何使用 symfony2 excelbundle 从 excel 文件中检索数据?

swift - 在Swift Docker 5.1.3中无法使用 'NSKeyValueObservation'

swift - 与 iOS 相比,我如何有条件地依赖桌面系统库?

c# - 混合交互行为给出 "points to immutable instance"错误