如果您在CocoaPods PodSpec文件中使用
resource
或
resources
,则告诉Cocoapods这些是您的库在运行时加载的资源文件。
如果您的库构建为动态框架,则这些文件只会复制到该框架的资源文件夹路径中,一切都将很好。但是,如果您的库构建为静态库,则这些文件将被复制到主应用程序包(
.app
)的资源文件夹中,这可能是一个问题,因为该主应用程序可能已经有了该名称的资源或另一个Pod可能有了该名称的资源,在这种情况下,这些文件将互相覆盖。而Pod是作为动态框架还是静态库构建的并未在PodSpec中指定,而是由集成您的Pod的应用程序的Podfile指定。
因此,对于具有资源的Pod,强烈建议改用
resource_bundles
!
在您的情况下,这些行
s.resource_bundles = {
'MySDK' => ['SDK/*/*.{xib,storyboard,xcassets}'] }
告诉CocoaPods创建一个名为
MySDK(
MySDK.bundle
)的资源包,并将所有匹配该模式的文件放入该资源包中。如果您的Pod是作为框架构建的,则此捆绑包位于框架捆绑包的资源文件夹中;如果作为静态库构建,则将该捆绑包复制到主应用程序捆绑包的资源文件夹中,如果您将捆绑包命名为与Pod相同的方式,则应该是安全的(您不应将其命名为“
MySDK”,而应该是“
SchedJoulesSDK”)。
此捆绑包将具有与您的Pod相同的标识符,但是当构建动态框架时,您的框架捆绑包也将具有该标识符,然后在通过标识符加载它时将加载哪个捆绑包是未定义的行为(在我的测试中,外部捆绑包总是获胜)。
正确的代码应该像这样(尚未经过测试):
let myBundle = Bundle(for: Self.self)
guard let resourceBundleURL = myBundle.url(
forResource: "MySDK", withExtension: "bundle")
else { fatalError("MySDK.bundle not found!") }
guard let resourceBundle = Bundle(url: resourceBundleURL)
else { fatalError("Cannot access MySDK.bundle!") }
let storyBoard = UIStoryboard(name: "SDK", bundle: resourceBundle)
由于resourceBundle
在运行时无法更改,因此只需创建一次(例如,在应用程序启动或初始化框架时)并将其存储在全局变量(或全局类属性)中即可安全使用,这样当需要时您就可以随时使用它(bundle对象也几乎不会使用任何RAM内存,因为它仅封装元数据):
final class SchedJoulesSDK {
static let resourceBundle: Bundle = {
let myBundle = Bundle(for: SchedJoulesSDK.self)
guard let resourceBundleURL = myBundle.url(
forResource: "MySDK", withExtension: "bundle")
else { fatalError("MySDK.bundle not found!") }
guard let resourceBundle = Bundle(url: resourceBundleURL)
else { fatalError("Cannot access MySDK.bundle!") }
return resourceBundle
}()
}
该属性是延迟初始化的(对于static let
属性来说,这是默认值,不需要使用lazy
关键字),系统确保只会发生一次初始化,因为let
属性一旦初始化后就不能更改。请注意,在此上下文中,您不能使用Self.self
,而需要使用实际的类名。
现在,您可以在代码中随时使用该bundle:
let storyBoard = UIStoryboard(name: "SDK",
bundle: SchedJoulesSDK.resourceBundle)