I'm try to implement ability to change interface in my program, something like themes. I'm decide to use bundles, so in my case they looks like this:
Theme1.bundle
Theme2.bundle
Every bundle have folders:
Theme1.bundle
graphic
pic1.png
pic2.png
sound
sound1.wav
sound2.wav
So I can get path to any required picture from bundle with this code:
path = [NSString stringWithFormat:#"%#.bundle/graphic/%#", selectedBundle, imageName];
When I get pictures from bundle there is no problem, path looks like this (I check it using breakpoints):
Theme1.bundle/graphic/pic1.png and I create UIImage
image = [UIImage imageNamed:path];
Pictures loaded without any problem.
But when I trying to play sound using AVAudioPlayer, I get path to sound by same way and path looks like this:
Theme1.bundle/sound/sound1.wav, but when I try to create NSData
sound = [NSData dataWithContentsOfFile:path];
it is not initialized.
When I try to keep sounds in main bundle and get it with
path = [[NSBundle mainBundle] pathForResource:#"sound1" ofType:#"wav"];
everything is OK, and path looks like this
/var/mobile/Applications/E8313E88-CE05-44B2-A80C-B05331D8596F/Myapp.app/sound1.wav
I cant understand why this works with pictures but not with sound?
Why I cant get sound from bundle?
Only one thing I can suggest - imageNamed: do some work to find right path to file and dataWithContentsOfFile: does not.
In your code instead of
sound = [NSData dataWithContentsOfFile:path];
Use
NSString * path = [NSString stringWithFormat:#"%#.bundle/sounds/%#", selectedBundle, soundName];
NSString *fullPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:path];
sound = [NSData dataWithContentsOfFile:path];
Explanation:
ImageNamed attaches the path of the application to the image name you specify
Related
I have an mp3 file in my Supporting Files folder which I would like to play in my app on a loop. I am using the following code to attempt this:
NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:#"smoothjazz" ofType:#"mp3" inDirectory:#"Supporting Files"];
NSURL *soundFileURL = [NSURL fileURLWithPath:soundFilePath];
AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithContentsOfURL:soundFileURL error:nil];
player.numberOfLoops = -1; //infinite
[player play];
However, this returns an error saying:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSURL initFileURLWithPath:]: nil string parameter'
How can I access my file in supporting files, and play it as intended? All help appreciated.
EDIT: SOLVED! See my answer for how I did it :)
If Supporting Files folder is the Supporting Files group you see in every Xcode project by default than the inFolder: argument is not needed as Supporting Files is a Xcode grouping and not a real folder. So you should do:
NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:#"smoothjazz"
ofType:#"mp3"];
This should work.
Hope it helps.
May be the path you getting through this will be nil,
NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:#"smoothjazz" ofType:#"mp3" inDirectory:#"Supporting Files"];.
Make sure you properly added the files to your bundle.
And add the proper checks before committing operations, its the best practice. Like follows, Hope this helps you..
// Define NSFileManager and add the proper checks for file existance like as follows.
NSFileManager *filemgr = [NSFileManager defaultManager];
NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:#"smoothjazz" ofType:#"mp3" inDirectory:#"Supporting Files"];
if (filemgr fileExistsAtPath:imageURL.absoluteString])
{
// Your code to play the sound file
}
Dan Spag was right - I didn't need to use 'inDirectory:', as it was in the supporting files. But the main problem was that I declared the AVAudioPlayer in the viewDidLoad method, meaning that it's lifespan was only as long as the method (or something along those lines). So I declared the variable as a global variable, and the problem was solved! The music plays.
I want to access data (xml, to be specific) in different filepaths, depending on some parameters. In short, theres a /Saves/ folder, which contains several other folders (/Save1/, /Save2/, /Save3/, etc). I want to be able to parse.
Lets assume the file I want to access is in the following path:
/../projectname/Saves/Save1/dialogue.xml
Within finder I created the folder substructure and then copied it into my XCode project. That means, these folders exist in the filestructure and not just in XCode.
Afterwards I'm trying to do the following:
NSString *path = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:"#/Saves/Save1/dialogue.xml"];
NSData *xmlData = [[NSMutableData alloc] initWithContentsOfFile:path];
However, that doesn't seem to work properly. Logging the path variable I get the following:
/Users/<username>/Library/Application Support/iPhone Simulator/5.1/Application/<appcode>/<appname>.app/Saves/Save1/dialogue.xml
Where's my mistake? Thanks in advance for any help.
Please make sure you have added same folder in project target also. One you add the same structure under project target and compile then same folders will be created in your .app file. then you can access it the way you mentioned.
try this:
//NSString *path = [[NSBundle mainBundle] pathForResource:#"dialogue" ofType:#"xml" inDirectory:#"Saves/Save1"];
NSString *path = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"Saves/Save1/dialogue.xml"];
if([[NSFileManager defaultManager] fileExitsAtPath:path])
{
NSMutableData *xmlData = [[NSMutableData alloc] initWithContentsOfFile:path];
}
else
{
NSLog(#"File doesnot exits");
}
I got "hello world" text to print after I hardcoded some html right into my UIWebView functions, but now I am trying to move that HTML to a file elsewhere on the file system, and it isnt rendering.
Here is what I have:
- (void)viewDidAppear:(BOOL)animated
{
NSString *htmlFile = [[NSBundle mainBundle] pathForResource:#"learn" ofType:#"html" inDirectory:#"src/html_files"];
NSString* htmlString = [NSString stringWithContentsOfFile:htmlFile encoding:NSUTF8StringEncoding error:nil];
[theWebView loadHTMLString:htmlString baseURL:nil];
}
and my HTML file is in a directory that I made called src/html_files and the file is named learn.html
What am I doing incorrectly that the HTML is not rendering on the screen?
Thank you!
Ok, so Groups are just a construct in Xcode for keeping your app's resources organized. Although Xcode uses the little folder icon, it doesn't necessarily mean those are actually separate folders on the (Mac or iOS) filesystem.
But, it sounds like you have added that file as a bundle resource. That's what the code you posted looks like, too, but I had to ask, to be sure.
Most likely, the only thing wrong is that this:
NSString *htmlFile = [[NSBundle mainBundle] pathForResource:#"learn"
ofType:#"html"
inDirectory:#"src/html_files"];
should be this instead:
NSString *htmlFile = [[NSBundle mainBundle] pathForResource:#"learn"
ofType:#"html"];
From the Apple documentation for NSBundle,
+ (NSString *)pathForResource:(NSString *)name
ofType:(NSString *)extension
inDirectory:(NSString *)bundlePath
bundlePath
The path of a top-level bundle directory. This must be a valid path. For example, to
specify the bundle directory for a Mac app, you might specify the path /Applications/MyApp.app.
The bundlePath parameter is not meant to specify relative paths to your bundle resources. The version of pathForResource:ofType: that does not have a bundlePath parameter is almost always what you'll use. It will find the learn.html file wherever it lives, once your app is installed, and return the full path to that. You don't really have to worry about how it's nested. It's just a bundle resource.
Give that a try. As I suggested in my comment, though, I always recommend taking advantage of the error parameter for debugging:
NSError* error;
NSString* htmlString = [NSString stringWithContentsOfFile:htmlFile encoding:NSUTF8StringEncoding error: &error];
if (error != nil) {
NSLog(#"Error with stringWithContentsOfFile: %#", [error localizedDescription]);
}
We have a web services function to which we are uploading an audio file into to be saved in the server. The code that I am using to create a data buffer (to pass to the web services) of the contents of the audio file is :
NSURL *soundFileURL = [[NSURL alloc] initFileURLWithPath:fnWithSlash];
audioData = [NSData dataWithContentsOfURL:soundFileURL];
NSLog(#"audiodata%d",audioData.length);
Here fnWithSlash contains the full path of the file. However audioData.length is always 0.
What am i missing?
Thanks in advance for your response.
Try using NSData's dataWithContentsOfFile: instead..If the file is in your bundle it will look like the example below, otherwise construct the filePath of the sound file to your desired location..
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"yourSound" ofType:#"wav"];
audioData = [NSData dataWithContentsOfFile:filePath];
NSLog(#"audiodata%d",audioData.length);
I am new to iPhone programming. I want to read the content of a text file located in a subfolder of the Resource folder.
The Resource folder structure is the following:
Resource
Folder1---->Data.txt
Folder2---->Data.txt
Folder3---->Folder1---->Data.txt
There are multiple files named "Data.txt", so how can I access the files in each folder? I know how to read the text file, but if the Resource structure is similar to the above structure then how can I get the path?
For example, if I want to access the "Data.txt" file from Folder3, how can I get the file path?
Please suggest.
Your "resource folder" is actually the contents of your main bundle, also know as the application bundle. You use pathForResource:ofType: or pathForResource:ofType:inDirectory: to get the full path for a resource.
Loading the contents of a file as a string is done with the stringWithContentsOfFile:encoding:error: method for an autoreleased string of with initWithContentsOfFile:encoding:error: if you want a retained string.
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"Data"
ofType:#"txt"
inDirectory:#"Folder1"];
if (filePath != nil) {
theContents = [NSString stringWithContentsOfFile:filePath
encoding:NSUTF8StringEncoding
error:NULL];
// Do stuff to theContents
}
This is almost the same answer as given by Shirkrin previously, but with the slight difference that it works on target. This is because initWithContentsOfFile: is deprecated on Mac OS X, and not available at all iPhone OS.
To continue psychotiks answer a full example would look like this:
NSBundle *thisBundle = [NSBundle bundleForClass:[self class]];
NSString *filePath = nil;
if (filePath = [thisBundle pathForResource:#"Data" ofType:#"txt" inDirectory:#"Folder1"]) {
theContents = [[NSString alloc] initWithContentsOfFile:filePath];
// when completed, it is the developer's responsibility to release theContents
}
Notice that you can use -pathForResource:ofType:inDirectory to access ressources in sub directories.
Shirkrin's answer and PeyloW's answer above were both useful, and I managed to use pathForResource:ofType:inDirectory: to access files with the same name in different folders in my app bundle.
I also found an alternative solution here that suited my requirements slightly better, so I thought I'd share it. In particular, see this link.
For example, say I have the following Folder References (blue icons, Groups are yellow):
Then I can access the image files like this:
NSString * filePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"pin_images/1/2.jpg"];
UIImage * image = [UIImage imageWithContentsOfFile:filePath];
As a side note, the pathForResource:ofType:inDirectory: equivalent looks like this:
NSString * filePath = [[NSBundle mainBundle] pathForResource:#"2" ofType:#"jpg" inDirectory:#"pin_images/1/"];
NSBundle* bundle = [NSBundle mainBundle];
NSString* path = [bundle bundlePath];
This gives you the path to your bundle. From there on, you can navigate your folder structure.