从Xcode 12.0开始,在Swift包中使用嵌入式故事板成为可能,但需要一些额外步骤才能确保正常工作。本文介绍如何实现在应用程序中加载和使用Swift包中的故事板资源。
场景与目标
假设有一个应用程序需要显示来自名为BadgeKit的Swift包中的故事板,该包使用Swift 5.3或更高版本,并包含一个名为BadgeKit.storyboard的故事板文件。目标是在应用程序故事板中添加故事板引用,并使其在运行时正确加载。
关键步骤与解决方法
1. 添加故事板引用到应用程序
在应用程序的故事板中,插入一个故事板引用,并配置以下属性:
- Storyboard: 设置为
BadgeKit(即Swift包中故事板的名称)。 - Bundle identifier: 设置为
BadgeKit-BadgeKit-resources。Xcode会自动为Swift包资源生成包标识符,格式为[包名]-[包目标名称]-resources。如果包名和目标名称相同(如BadgeKit),则标识符如上所示。
2. 解决资源包加载问题
Swift包资源包在构建时会被包含,但运行时可能不会自动加载,尤其是当应用程序仅通过故事板引用使用资源而没在代码中直接导入包时。这需要以下解决方法之一:
方法一:在AppDelegate中手动加载资源包
在应用程序的AppDelegate.swift文件中添加代码,强制加载资源包:
@UIApplicationMain final class AppDelegate: UIResponder {
override init() {
super.init()
// 工作区:故事板不会触发Swift包中资源包的加载
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数组包含资源包的文件名,Xcode自动命名为[包名]_[包目标名称].bundle。注意文件名与包标识符不同。
方法二:使用Bundle.module实例化故事板
在Swift包中添加视图控制器扩展,利用Bundle.module来加载故事板:
public extension UIViewController {
public static func getStoryboardVC() -> UIViewController {
let storyboard = UIStoryboard(name: String(describing: self), bundle: Bundle.module)
return storyboard.instantiateInitialViewController()!
}
}
然后在应用程序中调用此方法来实例化视图控制器:
@IBAction func openCard() {
let vc = MySwiftPackage.MyViewController.getStoryboardVC() as! MySwiftPackage.MyViewController
present(vc, animated: true, completion: nil)
}
3. 配置Swift包中的故事板
在Swift包的故事板文件中,确保视图控制器的模块设置正确:
- 手动选择Module为Swift包的目标名称(如
BadgeKit)。 - 取消勾选“Inherit Module From Target”,以避免模块继承问题。
总结与注意事项
- Xcode 14.2及更高版本更新:在这些版本中,包中的故事板会自动按需加载,可能不再需要上述解决方法。但对于早期版本,这些步骤仍然必要。
- 资源包管理:Swift 5.3引入了资源支持,通过在
Package.swift的.target中添加resources来声明资源,例如:
.target(name: "HelloWorldProgram", resources: [.process("Images"), .process("README.md")])
- 调试技巧:如果需要检查运行时加载的包,可以使用
Bundle.allBundles遍历并打印包标识符来排查问题。
通过以上步骤,您可以确保Swift包中的故事板在应用程序中正确加载和使用,避免因资源包未加载而导致的崩溃或显示问题。这些方法经过测试,适用于Xcode 12.0及更高版本,并兼容App Store发布流程。