在CocoaPods中使用资源包 [英] Use resource bundles in CocoaPods

查看:78
本文介绍了在CocoaPods中使用资源包的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在制作Pod(MySDK),并希望从 CocoaPods 生成的单独资源包中加载资产。

I am making a pod (MySDK) and would like to load the assets from the separate resource bundles CocoaPods generates.

但是,我无法正常工作。

However, I can not get it to work.

这是我尝试加载情节提要的方式:

Here is how I tried to load the storyboard:

let storyBoard = UIStoryboard(name: "SDK", bundle: Bundle(identifier:"org.cocoapods.SchedJoulesSDK"))

这会产生错误:


'找不到捆绑包中名为 SDK的情节提要

'Could not find a storyboard named 'SDK' in bundle

捆绑包已添加到Xcode中:

The bundle is added in Xcode:

我的 podspec 看起来像这样:

  s.resource_bundles = {
    'MySDK' => ['SDK/*/*.{xib,storyboard,xcassets}']
  }

有任何想法吗?

推荐答案

如果您使用 资源 资源 在CocoaPods PodSpec文件中,您告诉Cocoapods这些是库将在运行时加载的资源文件。

If you use resource or resources in a CocoaPods PodSpec file, you tell Cocoapods that these are the resource files your library will load during runtime.

如果您的库是作为动态框架构建的,则将这些文件复制到该框架的资源文件夹路径中,一切都会很好。但是,如果您的库是作为静态库构建的,则将它们复制到主应用程序捆绑包( .app )的资源文件夹中,这可能是一个问题,因为该主应用程序可能已经具有该名称的资源,或者另一个Pod可能具有该名称的资源,在这种情况下,这些文件将相互覆盖。 PodSpec并未指定是将Pod构建为动态框架还是静态库,而是由集成Pod的应用程序在Podfile中指定。

If your library is built as a dynamic framework, these files are just copied to the resource folder path of that framework and everything will be fine. Yet if your library is built as a static library, these are copied to the resource folder of the main application bundle (.app) and this can be a problem as this main application may already have a resource of that name or another Pod may have a resource of that name, in that case these files will overwrite each other. And whether a Pod is built as dynamic framework or as a static library is not specified by the PodSpec but in the Podfile by the application integrating your Pod.

因此Pod与资源,强烈建议使用 resource_bundles 代替!

Thus for Pods with resources, it is highly recommended to use resource_bundles instead!

在您的情况下,行

s.resource_bundles = {
    'MySDK' => ['SDK/*/*.{xib,storyboard,xcassets}'] }

告诉CocoaPods创建一个名为 MySDK MySDK.bundle )的资源束,并将所有与模式匹配的文件放入该资源束。如果您的Pod是作为框架构建的,则此捆绑包位于框架捆绑包的resources文件夹中;如果将其作为静态库构建,则将该捆绑包复制到主应用程序捆绑包的resources文件夹中,如果您使用与Pod相同的方式命名捆绑包,则该捆绑包应该是安全的(不应将其命名为 MySDK ,而不是 SchedJoulesSDK )。

tell CocoaPods to create a resource bundle named MySDK (MySDK.bundle) and place all files matching the pattern into that resource bundle. If your Pod is built as a framework, this bundle is located in the resources folder of your framework bundle; if it is built as a static library, the bundle is copied to the resources folder of the main application bundle, which should be safe if you name your bundle the same way as your Pod (you should not name it "MySDK", rather "SchedJoulesSDK").

此捆绑包的标识符与您的Pod相同,但是在构建动态框架时,那么您的框架包也将具有该标识符,然后是未定义的行为,即当您按标识符加载它时,哪个束将被加载(目前,外部束在我的测试中总是获胜)。

This bundle will have the same identifier as your Pod, however when dynamic frameworks are built, your framework bundle will have that identifier as well and then it's undefined behavior which bundle is being loaded when you load it by identifier (and currently the outer bundle always wins in my tests).

正确的代码如下所示(虽然未测试):

Correct code would look like this (not tested, though):

// Get the bundle containing the binary with the current class.
// If frameworks are used, this is the frameworks bundle (.framework),
// if static libraries are used, this is the main app bundle (.app).
let myBundle = Bundle(for: Self.self)

// Get the URL to the resource bundle within the bundle
// of the current class.
guard let resourceBundleURL = myBundle.url(
    forResource: "MySDK", withExtension: "bundle")
    else { fatalError("MySDK.bundle not found!") }

// Create a bundle object for the bundle found at that URL.
guard let resourceBundle = Bundle(url: resourceBundleURL)
    else { fatalError("Cannot access MySDK.bundle!") }

// Load your resources from this bundle.
let storyBoard = UIStoryboard(name: "SDK", bundle: resourceBundle)

As resourceBundle 在运行时无法更改,可以安全地创建一次(例如,在应用启动时或初始化框架时)并将其存储到全局变量(或全局类属性)中是安全的),因此您总是在需要时使用它(捆绑对象也几乎不使用任何RAM内存,因为它只封装元数据):

As resourceBundle cannot change at runtime, it is safe to create it only once (e.g. on app start or when your framework is initialized) and store it into a global variable (or global class property), so you have it always around when needed (a bundle object also hardly uses any RAM memory, as it only encapsulates meta data):

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 ,需要使用实际的类名。

The property is initialized lazy (that's default for static let properties, no need for the lazy keyword) and the system ensures that this happen only once, as a let property must not changed once initialized. Note that you cannot use Self.self in that context, you need to use the actual class name.

在您的代码,现在就可以在需要的地方使用该捆绑软件了:

In your code you can now just use that bundle wherever needed:

let storyBoard = UIStoryboard(name: "SDK", 
    bundle: SchedJoulesSDK.resourceBundle)

这篇关于在CocoaPods中使用资源包的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆