xcode 如何在 iOS 的 cocoapod 库中使用图像资产目录
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/32577227/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to use images asset catalog in cocoapod library for iOS
提问by mindbomb
I have a cocoapod library which contains assets in 2 formats:
我有一个 cocoapod 库,其中包含 2 种格式的资产:
- a .storyboard
- XCode asset catalog .xcassets (with images)
- .storyboard
- XCode 资产目录 .xcassets(带图像)
my podspec
file contains the definition for the resource bundle:
我的podspec
文件包含资源包的定义:
s.resource_bundle = {'SparkSetup' => ['Resources/**/*.{xcassets,storyboard}']}
and I have a separate target in the pod project to create a resource bundle by using those files + a plist file for that bundle.
我在 pod 项目中有一个单独的目标,用于通过使用这些文件 + 该包的 plist 文件来创建资源包。
thing is that when I use the pod in an app project - I can see the storyboard/xcassets files being in the pod target and I can access and run the storyboard easily but the images referenced in the storyboard (to the .xcassets file) are not found in run-time (but displayed correctly in IB).
事情是,当我在应用程序项目中使用 pod 时 - 我可以看到故事板/xcassets 文件位于 pod 目标中,我可以轻松访问和运行故事板,但故事板中引用的图像(到 .xcassets 文件)是在运行时找不到(但在 IB 中正确显示)。
Error I get is:
我得到的错误是:
Could not load the "spinner" image referenced from a nib in the bundle with identifier "(null)"
I do see a bundle file in the products directory. To instanciate VCs in the storyboard I use:
我确实在产品目录中看到了一个捆绑文件。为了在故事板中实例化 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;
}
which seems to work well for finding the storyboard, but not for finding images in the .xcassets in the same bundle.
这似乎适用于查找故事板,但不适用于在同一包中的 .xcassets 中查找图像。
What am I doing wrong? how can I reference images from this storyboard/from code and be able to integrate this UI pod into any app?
我究竟做错了什么?我如何从这个故事板/代码中引用图像,并能够将此 UI pod 集成到任何应用程序中?
Thanks!
谢谢!
回答by Chris Prince
At least as of version 1.0.1 of Cocoapods, image asset catalogs are supported.
至少从 Cocoapods 1.0.1 版本开始,支持图像资产目录。
In my Swift 4.2code, I used:
在我的Swift 4.2代码中,我使用了:
public static var GoogleIcon: UIImage {
let bundle = Bundle(for: self)
log.msg("bundle: \(bundle)")
return UIImage(named: "GoogleIcon", in: bundle, compatibleWith: nil)!
}
In my pod spec, I used:
在我的 pod 规范中,我使用了:
s.resources = "SMCoreLib/Assets/*.xcassets"
When I build using the simulator, the .car file doesshow up in the Framework:
当我使用模拟器构建时,.car 文件确实出现在框架中:
cd /Users/<snip>/SMCoreLib.framework
ls
Assets.car Info.plist SMCoreLib
回答by mindbomb
Well, image asset catalogs are not supported via pods - just include a resource bundle that contains your image files in your podspec like so:
好吧,Pod 不支持图像资产目录 - 只需在 podspec 中包含一个包含图像文件的资源包,如下所示:
s.subspec 'Resources' do |resources|
resources.resource_bundle = {'MyBundle' => ['Resources/**/*.{png}']}
end
and access the images safely from the pod like that:
并像这样从 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;
}
That solves all issues of handling images/resources within a cocoapod.
这解决了在 cocoapod 中处理图像/资源的所有问题。
回答by Daishi Nakajima
if you are using swift.
如果您使用的是 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
}
回答by Phil
Swift 3 version
斯威夫特 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()
}
回答by Okhan Okbay
Only this works for me (Swift 3 & Swift 4)
只有这对我有用(Swift 3 和 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")
}
}
Then use it as below:
然后按如下方式使用它:
ImagesHelper.myImage
As in the @Chris Prince's answer, don't forget to update your podspec file like:
正如@Chris Prince的回答一样,不要忘记更新您的 podspec 文件,例如:
s.resource_bundles = {
'YourClass' => ['YourPodName/*/Assets.xcassets']
}
回答by Abhishek Thapliyal
In you podspec do like this
在你的 podspec 中这样做
s.resources = 'RootFolder/**/*.{lproj,storyboard,xcdatamodeld,xib,xcassets,json}'
回答by jr00n
I can't still get it to work, with none of the solutions above. I have an Assets.xcassets file in my Pod.
没有上述解决方案,我仍然无法让它工作。我的 Pod 中有一个 Assets.xcassets 文件。
And inside my Pod classes i would like to access images from the Assets
在我的 Pod 类中,我想从 Assets 访问图像
Specified like this:
指定如下:
s.resource_bundles = {
'SWDownloadPlayButton' => ['SWDownloadPlayButton/Assets/Assets.xcassets']
}
With this helper:
有了这个助手:
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")
}
}
But whatever i do inside my Pod classes (not in the example project)...like this
但是无论我在 Pod 类中做什么(不在示例项目中)......就像这样
var centerImage: UIImage = ImagesHelper.download_icon.withRenderingMode(.alwaysTemplate) {
didSet {
updateImage()
}
}
I still get a nil on the centerImage
我仍然在 centerImage 上得到一个零
回答by levin varghese
回答by thexande
Add your .xcassets
file within the resources in your pod spec, and use the following UIImage init:
.xcassets
在 pod 规范中的资源中添加您的文件,并使用以下 UIImage init:
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)
}
}
回答by Brad Howes
My own solution to the issue with CocoaPods. Instead of mucking with UIImage, I added a method to Bundle instead. The method attempts to locate an inner bundle of a given name, but falls back to the original bundle. This allows the code to work in both the application code using pods, as well as the pod code itself.
我自己对 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
}
}
Then in the viewDidLoad
method or wherever else you have your image setting code, put something like this, where "ClassFromPod" refers to a Swift class from a CocoaPod, and "ResourceName" is the name of the inner bundle within the pod (you should be able to see the bundles using Xcode project navigator in "Pods/Projects" -- embedded bundles have a LEGO icon and have a "bundle" suffix.)
然后在viewDidLoad
方法或其他任何你拥有图像设置代码的地方,放置这样的东西,其中“ClassFromPod”指的是来自 CocoaPod 的 Swift 类,“ResourceName”是 pod 中内部包的名称(你应该是能够在“Pods/Projects”中使用 Xcode 项目导航器查看包——嵌入的包有一个 LEGO 图标并有一个“包”后缀。)
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)
As you can see, the UIImage API remains the same, only the bundle being used is different depending on what it finds at runtime.
如您所见,UIImage API 保持不变,只是使用的包根据运行时找到的内容不同而不同。