如何在iOS的cocoapod库中使用图像资产目录

时间:2015-09-15 03:30:00

标签: ios objective-c iphone xcode cocoapods

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

  • a .storyboard
  • XCode资产目录.xcassets(带图片)

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

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

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

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

我得到的错误是:

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

我确实在products目录中看到了一个bundle文件。 要在故事板中实现VC,我使用:

+(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集成到任何应用程序中?

谢谢!

11 个答案:

答案 0 :(得分:28)

至少从Cocoapods版本1.0.1开始,支持图像资产目录。

在我的Swift代码中,我使用了:

public static var GoogleIcon:UIImage {
    let bundle = NSBundle(forClass: self)
    Log.msg("bundle: \(bundle)")
    return UIImage(named: "GoogleIcon", inBundle: bundle,compatibleWithTraitCollection: nil)!
}

在我的pod规范中,我使用了:

s.resources = "SMCoreLib/Assets/*.xcassets"

当我使用模拟器构建时,.car文件 显示在框架中:

cd /Users/<snip>/SMCoreLib.framework 
ls
Assets.car  Info.plist  SMCoreLib

答案 1 :(得分:10)

嗯,通过pod不支持图像资产目录 - 只需在podspec中包含一个包含图像文件的资源包,如下所示:

s.subspec 'Resources' do |resources|
    resources.resource_bundle = {'MyBundle' => ['Resources/**/*.{png}']}

end

并安全地从pod中访问图像:

+(NSBundle *)getResourcesBundle
{
    NSBundle *bundle = [NSBundle bundleWithURL:[[NSBundle bundleForClass:[self class]] URLForResource:@"MyBundle" withExtension:@"bundle"]];
    return bundle;
}


+(UIImage *)loadImageFromResourceBundle:(NSString *)imageName
{
    NSBundle *bundle = [MyClass getResourcesBundle];
    NSString *imageFileName = [NSString stringWithFormat:@"%@.png",imageName];
    UIImage *image = [UIImage imageNamed:imageFileName inBundle:bundle compatibleWithTraitCollection:nil];
    return image;
}

解决了在cocoapod中处理图像/资源的所有问题。

答案 2 :(得分:4)

Swift 3版本

private func getImageFromBundle(name: String) -> UIImage {
   let podBundle = Bundle(for: YourClass.self)
   if let url = podBundle.url(forResource: "YourClass", withExtension: "bundle") {
      let bundle = Bundle(url: url)
      return UIImage(named: name, in: bundle, compatibleWith: nil)!
   }
   return UIImage()
}

答案 3 :(得分:3)

如果你使用swift。

class func loadImage(name: String) -> UIImage? {
    let podBundle = NSBundle(forClass: MyClass.self)
    if let url = podBundle.URLForResource("MyBundleName", withExtension: "bundle") {
        let bundle = NSBundle(URL: url)
        return UIImage(named: name, inBundle: bundle, compatibleWithTraitCollection: nil)
    }
    return nil
}

答案 4 :(得分:2)

只有这对我有用(Swift 3&amp; Swift 4)

public struct ImagesHelper {
  private static var podsBundle: Bundle {
    let bundle = Bundle(for: YourClass.self)
    return Bundle(url: bundle.url(forResource: "YourClass",
                                  withExtension: "bundle")!)!
  }

  private static func imageFor(name imageName: String) -> UIImage {
    return UIImage.init(named: imageName, in: podsBundle, compatibleWith: nil)!
  }

  public static var myImage: UIImage {
    return imageFor(name: "imageName")
  }
}

然后使用如下:

ImagesHelper.myImage

@Chris Prince的答案一样,请勿忘记更新您的podspec文件,如:

s.resource_bundles = {
  'YourClass' => ['YourPodName/*/Assets.xcassets']
}

答案 5 :(得分:2)

在你的podspec中你喜欢这个

s.resources = 'RootFolder/**/*.{lproj,storyboard,xcdatamodeld,xib,xcassets,json}'

答案 6 :(得分:1)

我仍然无法使用上面的任何解决方案。 我的Pod中有一个Assets.xcassets文件。

在我的Pod类中,我想从Assets中访问图像

指定如下:

s.resource_bundles = {
     'SWDownloadPlayButton' => ['SWDownloadPlayButton/Assets/Assets.xcassets']
}

使用此助手:

public struct ImagesHelper {
    private static var podsBundle: Bundle {
        let bundle = Bundle(for: SWDownloadPlayButton.self)
        return Bundle(url: bundle.url(forResource: "SWDownloadPlayButton",
                                      withExtension: "bundle")!)!
    }

    private static func imageFor(name imageName: String) -> UIImage {
        return UIImage.init(named: imageName, in: podsBundle, compatibleWith: nil)!
    }

    public static var download_icon: UIImage {
        return imageFor(name: "download_icon")
    }
}

但是我在Pod类中所做的任何事情(不在示例项目中)……都是这样

 var centerImage: UIImage = ImagesHelper.download_icon.withRenderingMode(.alwaysTemplate) {
        didSet {
            updateImage()
        }
    }

我在centerImage上仍然没有显示

答案 7 :(得分:0)

您可以使用其包ID来访问Pod中的图像

enter image description here

 NSBundle * bundle = [NSBundle bundleWithIdentifier:@"bundle id of your pod"];
UIImage * image = [UIImage imageNamed:@"imageName" inBundle:bundle compatibleWithTraitCollection:nil];

答案 8 :(得分:0)

在您的pod规范的资源中添加.xcassets文件,并使用以下UIImage初始化:

extension UIImage {
    convenience init?(podAssetName: String) {
        let podBundle = Bundle(for: ConfettiView.self)

    /// A given class within your Pod framework
    guard let url = podBundle.url(forResource: "CryptoContribute",
                                  withExtension: "bundle") else {
        return nil

    }

    self.init(named: podAssetName,
              in: Bundle(url: url),
              compatibleWith: nil)
    }
 }

答案 9 :(得分:0)

我自己对CocoaPods问题的解决方案。我没有使用UIImage进行处理,而是向Bundle中添加了一个方法。该方法尝试查找给定名称的内部捆绑包,但回退到原始捆绑包。这样一来,代码就可以在使用Pod的应用程序代码以及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项目导航器查看包-嵌入式包具有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保持不变,只是所使用的捆绑包有所不同,具体取决于它在运行时所找到的内容。

答案 10 :(得分: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"))