如何在iOS的Cocoapod库中使用图像资源目录?

31

我有一个cocoapod库,其中包含2种格式的资源:

  • .storyboard文件
  • Xcode的asset catalog .xcassets(带图像)

我的podspec文件包含资源包的定义:

s.resource_bundle = {'SparkSetup' => ['Resources/**/*.{xcassets,storyboard}']}

我在pod项目中有一个单独的目标,通过使用这些文件和一个plist文件创建资源包。

问题是,当我在应用程序项目中使用pod时,我可以看到storyboard /xcassets 文件位于pod目标中,并且可以轻松访问和运行storyboard,但是在运行时找不到storyboard中引用的图像(到.xcassets文件),但在Interface Builder中显示正确。

我得到的错误是:

Could not load the "spinner" image referenced from a nib in the bundle with identifier "(null)"

我在产品目录中看到一个捆绑文件。 在Storyboard中实例化VCs时,我使用以下内容:

+(NSBundle *)getResourcesBundle
{
    NSBundle *bundle = [NSBundle bundleWithURL:[[NSBundle mainBundle] URLForResource:@"SparkSetup" withExtension:@"bundle"]];
    return bundle;
}


+(UIStoryboard *)getSetupStoryboard
{
    UIStoryboard *setupStoryboard = [UIStoryboard storyboardWithName:@"setup" bundle:[SparkSetupMainController getResourcesBundle]];
    return setupStoryboard;
}

似乎可以很好地找到故事板,但无法在同一捆绑包中的.xcassets中找到图像。

我哪里做错了? 我该如何从故事板/代码引用图像并能够将此UI pod集成到任何应用程序中?

谢谢!


遇到完全相同的问题。我注意到,如果我使用没有资源目录的图像,它能够正常工作。 - bencallis
1
@bencallis 显然这是唯一的解决方案。 XCode 似乎无法引用未加载到主应用程序捆绑包中的资源目录.. 唯一的解决方案是更改 podspec 中的 resource_bundle 行以包括 .png 而不是 .xcasset,并逐个引用每个图像。虽然不完美,但这是唯一的可行方式.. - mindbomb
1
我也遇到了这个问题。甚至无法从pod中的xcasset目录使用imageNamed加载图像。:( - Jure
12个回答

0

关于CocoaPods问题的解决方案,我有自己的方法。我没有与UIImage打交道,而是在Bundle中添加了一个方法。该方法尝试查找给定名称的内部Bundle,但会回退到原始Bundle。这使得代码可以在使用pods的应用程序代码以及pod本身的代码中工作。

extension Bundle {

    /**
     Locate an inner Bundle generated from CocoaPod packaging.

     - parameter name: the name of the inner resource bundle. This should match the "s.resource_bundle" key or
       one of the "s.resoruce_bundles" keys from the podspec file that defines the CocoPod.
     - returns: the resource Bundle or `self` if resource bundle was not found
    */
    func podResource(name: String) -> Bundle {
        guard let bundleUrl = self.url(forResource: name, withExtension: "bundle") else { return self }
        return Bundle(url: bundleUrl) ?? self
    }
}

然后在`viewDidLoad`方法中或您设置图像的任何其他位置,添加如下内容,其中“ClassFromPod”指来自CocoaPod的Swift类,“ResourceName”是内部包的名称,您应该能够使用Xcode项目导航器中的“Pods/Projects”看到这些包 - 嵌入式包具有LEGO图标并具有“bundle”后缀。
super.viewDidLoad()
let bundle = Bundle(for: ClassFromPod.self).podResource(name: "ResourceName")
img1 = UIImage(named: "FancyBase", in: bundle, compatibleWith: nil)
img2 = UIImage(named: "FancyHandle", in: bundle, compatibleWith: nil)

正如您所看到的,UIImage API保持不变,只是根据运行时找到的内容使用不同的bundle。


0
如果你正在使用SwiftUI,那么使用Image.init(_ name: String, bundle: Bundle?)初始化器是行不通的。你需要像这样进行初始化:
 func getImage(named name: String) -> UIImage {
    // Use a random singleton class in your project.
    // Emphasis on class, structs won't work.
    let bundle = Bundle(for: [random class].self)

    if let image = UIImage(named: name, in: bundle, compatibleWith: nil) {
        return image
    }

    return .init()
}

Image(uiImage: getImage(named: "image_name"))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接