I would like to include image assets in a cocoapod library, but I'm having trouble accessing them. I've read these resources for help:
Cocoapods Resources
Cocoapods Resource Bundles
Mokacoding Resource Bundles
David Potter Resource Bundles
However, none point me in the direction of accessing the resources. I've tried the following:
[UIImage imageWithData:[NSData dataWithContentsOfURL:[(NSBundle *)[NSBundle bundleWithIdentifier:#"Assets"] URLForResource:#"my-image#2x" withExtension:#"png"]]]
[UIImage imageWithData:[NSData dataWithContentsOfURL:[(NSBundle *)[NSBundle bundleWithIdentifier:#"Assets"] URLForResource:#"my-image" withExtension:#"png"]]]
[UIImage imageWithData:[NSData dataWithContentsOfURL:[(NSBundle *)[NSBundle bundleWithIdentifier:#"Assets.bundle"] URLForResource:#"my-image" withExtension:#"png"]]]
[UIImage imageWithData:[NSData dataWithContentsOfURL:[(NSBundle *)[NSBundle mainBundle] URLForResource:#"my-image" withExtension:#"png"]]]
[[UIImage imageWithData:[NSData dataWithContentsOfURL:[(NSBundle *)[NSBundle mainBundle] URLForResource:#"my-image#2x" withExtension:#"png"]]]
[UIImage imageNamed:#"my-asset"]
[UIImage imageNamed:#"my-asset#2x.png"]
But none of them work.
I've setup my podspec with these alternatives and neither work with the above:
s.resources = ['Pod/Assets/*.{png, jpg}', 'Pod/Assets/**/*.{png, jpg}']
s.resource_bundles = {
'Assets' => ['Pod/Assets/*.{png, jpg}', 'Pod/Assets/**/*.{png, jpg}']
}
The resources show up under 'Development Pods/My App/Resources' after a pod update, but I cannot access them for the life of me. There aren't any bundles and there isn't anything named 'Assets'.
Any help or guidance would be appreciated.
It depends on the version of Cocoapods that you use. With older versions of cocoapods, you could get away with using [NSBundle mainBundle]:pathForResource:ofType:
NSString *bundlePath = [[NSBundle mainBundle]
pathForResource:#"MyResourceBundle" ofType:#"bundle"];
NSBundle *bundle = [NSBundle bundleWithPath:bundlePath];
If you are using newer Cocoapods and using spec.resource_bundles instead of spec.resources in your podspec file, you have to avoid mainBundle and replace it with NSBundle bundleForClass, which "Returns the NSBundle object with which the specified class is associated"
Example:
NSString *bundlePath = [[NSBundle bundleForClass:[MyFrameworkClass class]]
pathForResource:#"MyResourceBundle" ofType:#"bundle"];
NSBundle *bundle = [NSBundle bundleWithPath:bundlePath];
This tripped me up too. Maybe I'm misunderstanding +bundleWithIdentifier:, but I don't think you can use it to get to a resource bundle inside of your iOS app bundle. See the "Getting Bundles by Identifier" section of the bundle docs for more details.
What does work is +bundleWithPath:, e.g.:
NSString *bundlePath = [[NSBundle mainBundle] pathForResource:#"MyResourceBundle" ofType:#"bundle"];
NSBundle *bundle = [NSBundle bundleWithPath:bundlePath];
I wrapped that inside of a dispatch_once block and call it any time I need to access this bundle.
I'm using the s.resource_bundles syntax in my podspec as well and this works fine with it.
Related
When I try to get a UIImage from my project using NSBundle I get a nil value.
I have the image into .xcassests
This is my code to load image from bundle.
- (UIImage *)imageRating:(NSString *)imageName
{
return [UIImage imageNamed:imageName inBundle:[MyClass bundle] compatibleWithTraitCollection:nil];
}
And this is the Bundle Method.
+ (NSBundle *)bundle
{
return [NSBundle bundleForClass:[self class]];
}
Any idea why I get a nil value.
I guess the resource path is wrong.
Your image is placed in .xcassests and is finally packaged in the .app file, which is commonly used in main bundle.
If your project structure contains a framework, just if you get the current bundle in the framwork, then the path is not the resource under the main bundle, but the bundle resource of the framwork.
Because I don't know your project structure, the next step is to know the path to print the bundle and compare it with the main bundle path.
- (UIImage *)imageRating:(NSString *)imageName
{
NSBundle *bundle = [MyClass bundle];
NSBundle *mainBundle = [NSBundle mainBundle];
NSLog(#"bundle: %#\n main bundle: %#",imageBundle);
return [UIImage imageNamed:imageName inBundle:[MyClass bundle] compatibleWithTraitCollection:nil];
}
If the paths are different, there are two ways.
Put resources in the form of bundles in famework
Change [MyClass bundle] to [NSBundle mainBundle]
Using bundleForClass for retrieving bundle of framework where i have defined a class.
NSBundle *bundle = [NSBundle **bundleForClass**: [self class]]; // Class in framework
NSString *readtext = [bundle **pathForResource**:#"Test" ofType:#"rtf"];
Getting appbundle of application(Where i am using my framework) instead of framework bundle.
How to get framework bundle path and read the framework resources.
You can load NSBundle with Bundle Identifier of framework:
[NSBundle bundleWithIdentifier:YOUR_FRAMEWORK_BUNDLE_IDENTIFIRE];
If the framework has a resources bundle in it, then you can access the resources by:
NSBundle *bundle = [NSBundle bundleForClass:[YOUR_CLASS_NAME class]];
NSURL *url = [bundle URLForResource:RESOURCE_BUNDLE_NAME withExtension:#"bundle"];
NSBundle *resourceBundle = [NSBundle bundleWithURL:url];
UIImage* infoImage = [UIImage imageWithContentsOfFile:[resourceBundle pathForResource:#"info" ofType:#"png"]];
I'm always getting nil in url in the following code:
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
NSURL *url = [bundle URLForResource:#"Model" withExtension:#"momd"];
bundle is not nil, my model name is Model.xcdatamodeld
What can be wrong?
I don't think it is immediately obvious what bundleForClass is returning to you. Apple's docs say:
(NSBundle *)bundleForClass:(Class)aClass
Return Value:
The NSBundle object that dynamically loaded aClass (a loadable bundle), the NSBundle object for the framework in which aClass is defined, or the main bundle object if aClass was not dynamically loaded or is not defined in a framework.
It is only going to give you mainBundle under certain circumstances. You don't say what your class is. I think going straight to mainBundle (as you have done) is much safer.
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"DataModel" withExtension:#"momd"];
NSManagedObjectModel *mom = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
I cleared the Model.xcdatamodeld remove it, add new DataModel.xcdatamodel in my code and restart the simulator, then I got modelURL.
use
[[NSBundle bundleForClass:[self class]] resourceURL];
instead of
[NSBundle bundleForClass:[self class]];
I've added a new target of type Cocoa Touch Unit Testing Bundle to an existing iOS project, a test case and some jpg files that I need for testing.
I'm trying to load the image from the test bundle using the following code :
#implementation PhotosViewController_Tests : XCTestCase
-(void)addImage:(NSString *)imageName
{
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
NSString *imagePath = [bundle pathForResource:imageName ofType:#"jpg"];
UIImage *image = [UIImage imageWithContentsOfFile:imagePath];
...
}
However, bundle returns the main bundle, not the test bundle and imagePath and image are nil.
I can successfully load images from the main bundle (using this code), but I don't understand why bundleForClass returns the mainBundle instead of the unit test one.
I printed the [NSBundle allBundles] and I get the main bundle as well :
"NSBundle </var/mobile/Applications/uuid/Photos Light.app> (loaded)"
I guess it has something to do with adding the unit testing target after the project was created, but I can't figure what else to do to load images from the test bundle.
Try adding an extension to NSBundle in your test target that looks something like this...
#implementation NSBundle (MyAppTests)
+ (NSBundle *)testBundle {
// return the bundle which contains our test code
return [NSBundle bundleWithIdentifier:#"com.mycompany.MyAppTests"];
}
#end
Then when you need to load resources from your test bundle, import that category and then your code looks like...
NSString *imagePath = [[NSBundle testBundle] pathForResource:imageName ofType:#"jpg"];
UIImage *image = [UIImage imageWithContentsOfFile:imagePath];
Before I was loading me resources with the podspec:
s.resources = ["MyFramework/Resources/**/*.{xib, png, jpeg, jpg}"]
now I tried to accomplish the same with the following:
s.resource_bundles = {'Resources' => ['MyFramework/Resources/**/*.{xib, png, jpeg, jpg}']}
They appear to be copied as I can find them under:
Pods\Development Pods\MyFramework\Resources
But when I try to load them:
UIImage *testImage = [UIImage imageNamed:#"testImage.jpeg"];
the testImage is always nil.
I also tried to find out if there was somehow a bundle accessible so I would need to load an image from a created bundle but:
NSArray *bundles = [[NSBundle mainBundle] pathsForResourcesOfType:#"bundle" inDirectory:nil];
Revealed that no bundle was created through Cocoapods.
How exactly can I access those resources?
The resources is put in a bundle called 'Resources'.
s.resource_bundles = {'Resources' => ['MyFramework/Resources/**/*.{xib, png, jpeg, jpg}']}
you can access the bundle by the following code
NSBundle *bundle = [NSBundle bundleWithPath:[[NSBundle mainBundle]
pathForResource:#"Resources"
ofType:#"bundle"]];
The key in the s.resource_bundles is the bundle name.
Note:
I have some bundles listed by the following code. You may have other issues in your pod settings.
NSArray *bundles = [[NSBundle mainBundle] pathsForResourcesOfType:#"bundle" inDirectory:nil];
To load an image from a bundle use:
UIImage *testImage = [UIImage imageNamed:#"Resources.bundle/testImage.jpeg"];