If I include a folder in my bundle (a real folder, the blue ones, not the yellow groups), how can I get the path for that folder from my bundle? The method I would usually use is...
[[NSBundle mainBundle] pathForResource:fileName ofType:______];
...but what "type" is a directory? Is there a "type" to use, or is there another method for accessing the paths of directories within the bundle?
Or am I going about this all wrong, and there's some other way for including folders of accessible documents in the bundle?
Directories can have extensions too. If yours doesn't have one, just pass #"" for the type parameter, -[NSBundle pathForResource:ofType:] works for directories too, not only files. At the end, a directory is also a resource :)
As per a suggestion in the comments, it turns out you can use an empty string to refer to folders. So a folder called "myFolder" would be accessible using...
[[NSBundle mainBundle] pathForResource:#"myFolder" ofType:#""];
Hope this helps anyone else who wasn't expecting it to be so easy...
As you're adding a folder by your own, you know the name of the folder, so you can get the path like this:
NSString *myDirectoryName = #"myDirectory";
NSString *absolutePathToMyDirectory = [[NSBundle mainBundle].resourcePath stringByAppendingPathComponent:myDirectoryName];
You'll have to test if this path exist with NSFileManager.
Otherwise you can still use the method you're using, the type can be nil, so you can call it like this
NSString *absolutePathToMyDirectory = [[NSBundle mainBundle] pathForResource:myDirectoryName ofType:nil];
and then testing if the result is nil or not.
if(absolutePathToMyDirectory) {
// do stuff related to this path
}
Related
I've been using localization in my app, but for some reason, some of the strings (not all of them) won't translate, I see the key instead the value. I've tried to check if the app finds the localization files by doing this:
NSString *enPath = [[NSBundle mainBundle] pathForResource:#"en" ofType:#"lproj"];
NSString *hePath = [[NSBundle mainBundle] pathForResource:#"he" ofType:#"lproj"];
NSString *ruPath = [[NSBundle mainBundle] pathForResource:#"ru" ofType:#"lproj"];
NSString *esPath = [[NSBundle mainBundle] pathForResource:#"es" ofType:#"lproj"];
NSString *frPath = [[NSBundle mainBundle] pathForResource:#"fr" ofType:#"lproj"];
NSString *arPath = [[NSBundle mainBundle] pathForResource:#"ar" ofType:#"lproj"];
And none of them is nil.
I've checked the name of the localization file and it's Localizable.strings as it should be.
Also checked if the key exists inside the Localizable.strings files and it does.
I've also tried:
Empty Cache
Cleaning all targets
Delete Derived Data folder
Restart
Reset simulator
Convert to UTF-16
Remove all localization files and recreate them.
Also tried to do everything that is in this question.
It's important to say that this is not just a Simulator/Cache problem. It's also showing on devices which download the app. (I have Enterprise account).
What more can I do in order to identify nor fix the problem?
So I found the problem, I guess who translated the Localizable.strings files for me is an asshole. In 4 places in my strings file there was a row as followed:
"KEY" ;= "Value"
This line cause some kind of a crash, but let the compiler to build successfully for some reason. That's why I couldn't find the bug, only when I decided to take the last Key and Value which are not translate and move them to the top of the Localizable.strings file. Then I was able to understand and see that the problem is somewhere in the middle of the file and the top Keys and Values are translated fine.
One thing that you can do catch these kind of errors is to make a copy of the strings file, change the extension to plist and try to open it in Xcode. If there is any problem in the strings file it will show in Xcode since the dictionary will contain only the keys till the point where there is an error. You can then do a Find operation and find the error until you are sure that all strings appear in the plist file. You can then rename the file back to .strings
If you specify table:nil, then NSBundle will try to fetch the localization from the default table (the one in SOMELANG.lproj/Localizable.strings). If you have the localization elsewhere, you should explicitly specify the table using table:#"File" (or use the NSLocalizedStringFromTable() macro in a similar manner:
NSString *value = NSLocalizedStringFromTable(#"key", #"File", nil);
Also,
Double check that the Localizable.strings file is being added to
Targets -> BuildPhases -> Copy Bundle Resources
It hadn't been added automatically for me.
I have images.xcassets listed ounder copy bundle resources, and I did try to just state the file name by itself: MSB_big_icon , before trying to add the path within images.xcassets.
Can anybody tell me what I'm doing wrong?
NSString *path = [[NSBundle mainBundle]pathForResource:#"/Raymio_android_images/MSB_big_icon.imageset/MSB_big_icon" ofType:#"png"];
NSLog(#"path: %#", path);
MSBIcon *tilecon = [MSBIcon iconWithUIImage:[UIImage imageWithContentsOfFile:path] error:&error];
David Ansermot is right that xcassets is a much better approach and strongly preferred. If you can't use that (running on older versions of iOS for instance), still put everything in one directory and use imageNamed:. This has significant caching benefits over hand-loading the file.
An asset catalog (xcassets) is a (relatively) new, unified way of managing image resources. The images are no longer accessible as separate files on the disk. Instead, imageNamed: consults the asset catalog and fetches the correct asset.
Prior to asset catalogs (and still, for non-images), assets were stored in localized directories. All of your unlocalized assets would be put into a directory called Resources (no matter where those files might appear to be in your source tree, and no matter how those files might be arranged in your Xcode folders). Localized files would be stored in directories like English.lproj or French.lproj. When you make NSBundle calls to load MyImage, it looks at each localized directory in the order the user has configured, and if it cannot find it in any of those directories, it looks in Resources.
Now it is possible to store full directories as "a resource" by marking them as directory references in Xcode. In that case, the whole directory would be copied into Resources or the appropriate localized directory. In order to find files inside such a directory you can use the ...inDirectory: version of the NSBundle methods.
So most of the time, you want to just use imageNamed:, which is going to fetch things out of the asset catalog if available, and then search localized directories, and then look in Resources. If you need to find a non-image, or if for some reason you want the real path to the file, you can compute it like this:
NSString *path = [[NSBundle mainBundle] pathForResource:#"MSB_big_icon" ofType:#"png"];
And if that resource were in a directory tree (because it was a directory reference in Xcode), you can access it like this:
NSString *path = [[NSBundle mainBundle] pathForResource:#"MSB_big_icon"
ofType:#"png"
inDirectory:#"Raymio_android_images/MSB_big_icon.imageset"];
Here's a code exemple from one of my apps :
NSString *appKey = #"Applications__GENERIC";
NSString *path = [[NSBundle mainBundle] pathForResource:appKey ofType:#"plist"];
appData = [NSDictionary dictionaryWithContentsOfFile:path];
The "Applications__GENERIC.plist" is stored like this :
Other solutions :
Use the images.xcassets.
Then in your code to load an image, use the code :
UIImage *image = [UIImage imageNamed:#"MyImageWithoutExtension"];
Don't put any path or extension, only the image's name
Try using this:
NSString *path = [[NSBundle mainBundle] pathForResource:#"MSB_big_icon" ofType:#"png" inDirectory:#"Raymio_android_images/MSB_big_icon.imageset"];
What you can also do to debug is to print out
[[NSBundle mainBundle] bundleURL]
Then navigate to that folder and see if the folder structure corresponds to the path you use.
I just struggled with this today, hope it works out for you too.
I saw quite a few questions regarding [NSBundle MainBundle] pathForResource (using inDirectory or not), but my case seems different.
My problem is: Yes, it works fine for whatever files in subdirectory if without localization. For example, it returns the correct path for the file data/a/words.txt when I use
[[NSBundle mainBundle] pathForResource:#"words.txt" ofType:nil inDirectory:#"data/a"]
However, after I localized the words.txt, let's say the real path becomes: data/a/en.lproj/words.txt, then the above code cannot find the path anymore.
I checked the file in the .app package and the file has been copied into the correct path (data/a/en.lproj), it's just somehow the code cannot find it.
I'm using XCode 5.1.1
Isn't pathForResource supposed to find the text automatically?
Try adding forLocalization to pathForResource, like this:
NSArray* availableLocalizations = [[NSBundle mainBundle] localizations];
NSArray* userPrefered = [NSBundle preferredLocalizationsFromArray:availableLocalizations forPreferences:[NSLocale preferredLanguages]];
NSString *indexPath = [[NSBundle mainBundle] pathForResource:#"words" ofType:#"txt" inDirectory:#"data/a" forLocalization:[userPrefered objectAtIndex:0]];
My project has a folder (not group) named "data" which contains many subfolders, each of which contains a set of files.
My question is, how do I grab a URL (or path) reference to the "data" folder? How about to its subfolders? I'm sure it's a fairly simple task, so forgive my ignorance, but I've never used folder refs in a project so I'm not familiar with the code. I did look over the NSFileManager ref but I'm fuzzy on how to make use of it.
Thanks in advance.
NSBundle can give you your absolute path in the system.
NSString (or NSURL) has methods for working with paths.
NSFileManager allows you to move, copy, delete (…) files.
This is how you get path to your Data directory:
NSString *dataDir = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:#"Data"];
// "/var/private/Application/.../YourApp.app/Data"
Now you just append multiple directory names to dataDir using the same method above and you should get any path you want.
In case you don't know the exact path and you want to scan the directory, you will have to use
:
NSArray *dataDirContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:dataDir error:nil]
// "file1.data", "file2.data", ...
Then it's all about appending path components.
I am testing the MixerHost sample code. However the following code:
NSURL *beatsLoop = [[NSBundle mainBundle] URLForResource: #"beatsMono"
withExtension: #"caf"];
the beatsLoop is nil.
What's the reason for that?
Should I first create the beatsMono.caf file and then put into some specific path?
Any comments and solutions will be highly appreciated.
Thanks,
finspoo
Should I first create the beatsMono.caf file and then put into some specific path?
Yes. The file beatsMono.caf (case sensitive!) must exist in your application bundle for that method to succeed. This is done by adding the file to the target as a resource in XCode, you cannot do it at runtime.