2つの形式のアセットを含むココアポッドライブラリがあります。
podspec
ファイルには、リソースバンドルの定義が含まれています。
s.resource_bundle = {'SparkSetup' => ['Resources/**/*.{xcassets,storyboard}']}
そして、これらのファイルとそのバンドルのplistファイルを使用してリソースバンドルを作成するために、ポッドプロジェクトに別のターゲットがあります。
私がアプリプロジェクトでポッドを使用すると、ストーリーボード/ xcassetsファイルがポッドターゲットにあることがわかり、ストーリーボードに簡単にアクセスして実行できますが、ストーリーボードで参照される画像(.xcassetsファイル)はランタイムには見つかりません(ただし、IBでは正しく表示されます)。
私が得るエラーは:
Could not load the "spinner" image referenced from a nib in the bundle with identifier "(null)"
製品ディレクトリにバンドルファイルがあります。私が使用するストーリーボードで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ポッドをアプリに統合するにはどうすればよいですか?
ありがとう!
少なくともCocoapodsのバージョン1.0.1では、画像アセットカタログがサポートされています。
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)!
}
ポッド仕様では、次を使用しました。
s.resources = "SMCoreLib/Assets/*.xcassets"
シミュレーターを使用してビルドすると、.carファイルdoesがフレームワークに表示されます。
cd /Users/<snip>/SMCoreLib.framework
ls
Assets.car Info.plist SMCoreLib
さて、画像アセットカタログはポッドではサポートされていません-画像ファイルを含むリソースバンドルをポッドスペックに含めるだけです:
s.subspec 'Resources' do |resources|
resources.resource_bundle = {'MyBundle' => ['Resources/**/*.{png}']}
end
そのようなポッドから安全に画像にアクセスします。
+(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;
}
これにより、ココアポッド内の画像/リソースの処理に関するすべての問題が解決されます。
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()
}
あなたにポッドスペックでこのようにします
s.resources = 'RootFolder/**/*.{lproj,storyboard,xcdatamodeld,xib,xcassets,json}'
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
}
これは私のためにのみ機能します(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")
}
}
次に、以下のように使用します。
ImagesHelper.myImage
@ Chris Prince の答えのように、次のようにpodspecファイルを更新することを忘れないでください。
s.resource_bundles = {
'YourClass' => ['YourPodName/*/Assets.xcassets']
}
上記の解決策がないため、まだ動作しません。ポッドにAssets.xcassetsファイルがあります。
そして、私のPodクラス内で、アセットから画像にアクセスしたいと思います
次のように指定されます:
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")
}
}
しかし、私は私のポッドクラスの中で何をしても(サンプルプロジェクトではありません)...このように
var centerImage: UIImage = ImagesHelper.download_icon.withRenderingMode(.alwaysTemplate) {
didSet {
updateImage()
}
}
私はまだcenterImageにnilを取得しています
ポッド仕様のリソース内に.xcassets
ファイルを追加し、次の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)
}
}
CocoaPodsの問題に対する私自身の解決策。 UIImageをいじる代わりに、Bundleにメソッドを追加しました。このメソッドは、指定された名前の内部バンドルを見つけようとしますが、元のバンドルにフォールバックします。これにより、ポッドを使用するアプリケーションコードとポッドコード自体の両方でコードを機能させることができます。
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アイコンがあり、「バンドル」サフィックスがあります。)
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は同じままで、使用されているバンドルのみが実行時に検出されるものによって異なります。