iPhone SDK: subFolders inside the main bundle - iphone

in the current project I have a number of folders, with subfolders, and these contain images: 01.png, 02.png.
Folder1/FolderA/f1.png
Folder1/FolderB/F1.png
When I compile the app, I looked inside the the .app and noticed that all the images are placed in the top level, with no sub-folders.
So clearly when trying to load the image this doesn't work:
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"f1"
ofType:#"png"
inDirectory:#"Folder1/FolderA"];
But even more strangely, when loading image "f1", the image actually loads "F1"
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"f1.png"]];
Anyone have ideas on how to get around this problem?
Is there a compile option to create the folders in the app bundle?
TIA.

To create the subfolders inside the .app bundle, you should check the option "Create folder references for any added folders" rather than the default "Recursively create groups for any added folders"
Now in XCode, your imported folder appears blue rather than yellow. Build and go and you should see folders in your .app file.

First of all the folders you create in Xcode are simply organizational structures without any counterpart on the filesystem level. In other words all folders except for the "Classes" folder gets flatten out at the filesystem level. Therefore, even if you put your image file in the following location within xcode, it would still exist at the top-level in the filesystem: f1/f2/f3/f4/f5/image.png. Thus, in pathForResource method, you should not include the inDirectory argument.
As for the second issue, mac osx doesn't recognize case-sensitive file names. Therefore, f1 and F1 are equivalent to mac osx and will reference the same file. You can easily see this by executing the following 2 commands at a terminal session:
touch f
touch F
you'll notice that only 1 file exists after this: namely f. If you reverse the 2 commands, you still get one file, but it is named F.

ennuikiller is right. I think you can organize your images via Finder in subfolder and then refresh the image location in XCode by right clicking your image and selecting "Get Info" option. Then set the new directory.
Cheers.

Just wanted to add to Mugunth's answer, to follow up on part of the original question which was trying to use:
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"f1" ofType:#"png" inDirectory:#"Folder1/FolderA"];
... to access files added using folder references. The above 'pathForResouce' call will work on simulators but not on actual iPhones (nil will be returned), because they don't seem to recognize subfolders in the 'inDirectory' part of the method. They do recognize them in the 'pathForResource' part, though. So the way of rephrasing the above so that it works on iPhones is:
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"FolderA/f1" ofType:#"png" inDirectory:#"Folder1"];

I've followed your answer but it seams all files are stored flat on the root. If I use the code below to get the full path
CFBundleRef mainBundle = CFBundleGetMainBundle();
CFURLRef url = CFBundleCopyResourceURL(mainBundle, CFSTR("About"), CFSTR("png"), NULL);
UInt8 filePath[PATH_MAX];
CFURLGetFileSystemRepresentation(url, true, filePath, sizeof(filePath));
I get as a result: /Users/iosif/Library/Application Support/iPhone Simulator/6.1/Applications/33FB4F79-999C-4455-A092-906A75226CDB/Arithmetics.app/About.png

Related

Why can't I use the plist I created?

I created a plist called list.plist, I just can't read the information in it.
NSString *path = [[NSBundle mainBundle] bundlePath];
NSString *datapath = [path stringByAppendingPathComponent:#"list.plist"];
NSArray *array = [[NSArray alloc] initWithContentsOfFile:datapath];
self.tableDataSource = array;
NSLog(#"%d", [tableDataSource count]);
When I run it, it says the count is 0, but if I change file name to Elements.plist(a plist from the sample code from Apple), it will work. The two files are in the same path. list.plist is written by myself, it won't work even I copy the dictionary from elements.plist to list.plist.
File names are case-sensitive on iOS, FYI. Also, try renaming the Elements.plist from the sample to list.plist and trying again. Maybe it's about file contents, not about file name.
Check to see if the file you created is included in the "Copy Resources" phase of your build. This is necessary to make sure it gets copied from your project's directory to the location of the bundle at runtime.
In Xcode 4, you can do by selecting the project at the top of the project navigator.Click on the "Build Phases" tab and expand the "Copy Bundle Resources" section. You should see a list of files there that get copied. If you see the Elements.plist file but not list.plist, then that is your problem. Drag list.plist from the project navigator to the list of copied files and rebuild.

pathForResource yields erratic null

I have some problems adding my shader-glsl files from one xcode project to another. I'm completely confused at this moment, since I can't make a path to files I simply drag into xcode.
I have checked spelling, "show in finder" many times and still have the problem...
Here's my example of files I added to xCode, I didn't even put them into sub-directories to rule out any problems with those:
Now my code:
NSLog(#"Filepath of Tools-image: %#",[[NSBundle mainBundle] pathForResource:#"tools" ofType:#"png"]);
NSLog(#"Filepath of mo-tut is: %#",[[NSBundle mainBundle] pathForResource:#"mo" ofType:#"tut"]);
NSLog(#"Filepath of FragShader-fsh is: %#",[[NSBundle mainBundle] pathForResource:#"fragshader" ofType:#"fsh"]);
At run-time I get this output:
2011-07-02 02:03:33.516 windowconfig[16192:707] Filepath of Tools-image: /var/mobile/Applications/BC82AD2C-B8B9-4751-80A2-31EC5ACEC9C2/windowconfig.app/tools.png
2011-07-02 02:03:33.526 windowconfig[16192:707] Filepath of mo-tut is: /var/mobile/Applications/BC82AD2C-B8B9-4751-80A2-31EC5ACEC9C2/windowconfig.app/mo.tut
2011-07-02 02:03:33.531 windowconfig[16192:707] Filepath of FragShader-fsh is: (null)
Please, does anyone have an idea on this?
EDIT: "tools.png" currently is an icon I use on a tab-bar, its in a subfolder in resources and was just a test for comparison. In case you guys wonder why I didn't open the path to the other file in the screenshot.
EDIT2: I used "Clean" like crazy in the last two hours. "fragshader.fsh" appearently doesn't get copied to the "windowconfig.app" bundle even though I added it to the project in the same way I added "mo.tut" and this one is in the bundle package. How can I ensure it gets copied?
EDIT3: Target Membership is checked in the Inspector for both files, still teh shader isn't copied.
Solution:
Under Target-Build Phases the file wasn't in the "copy files to bundle" list.
I manually added it, but still its strange it wasn't added automatically after I added the file to the project.
Have you made sure that fragshader.fsh is in a copy files step? (i.e. made sure it's actually present in the resulting app bundle).

how to say to Xcode that this file is stored on <myApp>/documents (iPhone)

i'm new as an iphone developer, as a hobby i'm writting a small game (just for fun).
i would like to store the default configuration inside a xml file. I have the xml file, I know about how to parse the xml document, but.. what i do not know, and that's why i'm here is:
is there a way to say to Xcode: imagine this (xml) file is stored on /documents/ ? or the unique way is to copy&paste the (xml) file here:
~/Library/Application Support/iPhone Simulator/4.1/Applications//documents/
thanks!
fyi: the xml will always be together with the app.
just drag the xml into the file tree (solution explorer) in xcode
then to get the root directory path, just call
[[[NSBundle mainBundle] bundlePath] UTF8String]
that gets it as a char*, for c style string stuff. otherwise just leave out the UTF8String
[[NSBundle mainBundle] bundlePath] to get the NSString. just add your file name to the end
in my experience, it doesn't matter where you dump your xml in the 'solution explorer' it always ends up in the root directory.
better to use plist instead of xml . if u use plist then there is no need to parse it again.
end then use
NSString *theFolderPath = [NSHomeDirectory() stringByAppendingPathComponent:#"documents/YOUR FILE NAME"]

Can you build an array of items from folder contents?

Let's say I've got a folder in my project with bunch of png files in it (or mp3 files, or mov files etc).
I would like to create an NSArray populated with the items within that folder... for instance an array of UIImages for the folder of images (or just an array of NSStrings of the image name).
Is this possible? I know I could create a plist with all the names in, or name the items individually within the code, but this would break the DRY (don't repeat yourself) rule.
Has anyone worked this out?
Try NSFileManager's
- (NSArray *)contentsOfDirectoryAtPath:(NSString *)path error:(NSError **)error
Or, if your resources are in the app bundle, use -[NSBundle pathsForResourcesOfType:inDirectory:] as in
NSArray* mp3s=[[NSBundle mainBundle] pathsForResourcesOfType:#"mp3" inDirectory:nil];
Passing nil to the directory parameter defaults to the top level in the app bundle on iPhone, Resources/ in the OS X.

NSHomeDirectory returns different path each time iPhone App is restarted

I noticed that NSHomeDirectory returns a different path each time i restart the App with Xcode, and apparently even if i click the icon manually since it doesn't load the file's contents. I'm stunned that it gives me a different directory each time i restart the app. This happens on both simulator and device and even if i use the "ForUser" method. My calls look like this:
NSString* fullPath = [NSHomeDirectory() stringByAppendingPathComponent:#"test.file"];
or
NSString* fullPath = [NSHomeDirectoryForUser(#"MrX") stringByAppendingPathComponent:#"test.file"];
or even
NSString *docsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *path = [docsDirectory stringByAppendingPathComponent:#"test.file"];
And the log of two app starts looks like this, notice how the GUID part has changed:
loadCharacters: /var/mobile/Applications/ABE7E33E-439B-4258-8FC1-127A3CD00D87/test.file
loadCharacters: /var/mobile/Applications/71C02507-6347-4693-8CC1-537BE223179E/test.file
What am i doing wrong, or what am i missing?
SOLUTION:
At first i was saving to NSHomeDirectory itself, not the "Documents" subdirectory. Since the App directory changes with each deployment but only the files in the "Documents" directory get copied, the saved file was lost after each deployment. Then i used the "Documents" folder but someone suggested i should probably put it in a subfolder of "Documents" i did just that but forgot to create the folder, hence the file wasn't saved. I double-failed on this one. :)
Simply saving to NSHomeDirectory() + "Documents/test.file" works.
You're doing this correctly. Each time an app is installed into the simulator or device, it's placed into a different directory (I'm not sure why, but that's what happens). However, all of its directory structure is moved to the new position. Thus, your RELATIVE paths will remain unchanged.
The GUID portion of an app's home directory appears to be just a random UUID (as indicated by the 3rd group of hex digits starting with a '4' and the 4th group starting with '8','9','A' or 'B'. See the wikipedia entry on 'universally unique identifier' as a good starting place if you want to learn more about UUIDs and unique IDs in general. The reason for using a unique id in the directory path is just to separate one app (and multiple deploments of the same app) from one another as part of sandboxing (IMHO).