Xcode Folder References

I decided to write about something a bit more technical for this week’s iDevBlogADay post: Xcode Folder References. They’re really quite simple, but I keep seeing projects that don’t use them when they should.

What are folder references?

There are two types of folders in Xcode: groups and folder references. You can use groups to organize files in your project without affecting their structure on the actual file system. This is great for code, because you’re only going to be working with your code in Xcode. On the other hand, groups aren’t very good for resource files.

On any reasonably complicated project, you’ll usually be dealing with dozens – if not hundreds – of asset files, and those assets will need to be modified and manipulated from outside of Xcode, either by you or a designer. Putting all of your resource files in one flat folder is a recipe for disaster. This is where folder references come in. They allow you to organize your files into folders on your file system and keep that same folder structure in Xcode.

Creating folder references

You can create folder references by ticking the “Create Folder References for any added folders” radio button when you’re adding files to your project.

You’ll now see little blue folders in your project instead of yellow folders. The blue folders are folder references. Pretty simple.

Using folder references in code

Unlike with groups, when you use folder references you have to specify the full path to the file. If you’re using UIImage’s imageNamed, this is really easy:

UIImage *image = [UIImage imageNamed:@"Cats/Dogs/someImage.png"];

Unfortunately, you usually won’t be using imageNamed, you’ll be using imageWithContentsOfFile, or some other method that requires a full file path, so things get a tiny bit more complicated. You’ll have to get the path of the file from the bundle:

NSString *fullPath = [[NSBundle mainBundle] pathForResource:@"someImageFile.png" ofType:nil inDirectory:@"Cats/Dogs"];
UIImage *image = [UIImage imageWithContentsOfFile:fullPath];

Ok, that works, but wouldn’t it be nice if we didn’t have to split the path into two separate strings? Luckily Apple has provided a couple methods for doing exactly that in the (NSStringPathExtensions) category: lastPathComponent and stringByDeletingLastPathComponent

NSString *imagePath = @"Cats/Dogs/someImageFile.png";
NSString *fullPath = [[NSBundle mainBundle] pathForResource:[imagePath lastPathComponent] ofType:nil inDirectory:[imagePath stringByDeletingLastPathComponent]];
UIImage *image = [UIImage imageWithContentsOfFile:fullPath];

Great! But now our code has become really long winded, so let’s simplify this with a macro(you could also use a C function, a class method, or even a category on NSString).

#define GetFullPath(_filePath_) [[NSBundle mainBundle] pathForResource:[_filePath_ lastPathComponent] ofType:nil inDirectory:[_filePath_ stringByDeletingLastPathComponent]]
UIImage *image = [UIImage imageWithContentsOfFile:GetFullPath(@"Cats/Dogs/someImageFile.png")];

Anything else?

Yes! When you’re using folder references, you usually have to do a clean every time you do a build if you’ve changed any of the assets. In the process of writing this blog post, I stumbled upon this article on folder references by @MajicDave. Our posts cover some similar ground, but his goes into detail about how to solve this issue so that you no longer have to do a clean. Very handy.

This entry was posted in iDevBlogADay, iOS Development, Workflow. Bookmark the permalink.

12 Responses to Xcode Folder References

  1. Pingback: How To Use Xcode’s Folder References | iPhone iOS 4 iTV iPad SDK Development Tutorials, Programming Tips, News

  2. Pingback: Xcode Folder References « Thoughts at Micro Unlimited

  3. Pingback: How To Use Xcode’s Folder References | MarketingTypo.com

  4. Goffredo Marocchi says:

    Using your define:
    #define BUNDLE_FULL_PATH(_filePath_) [[NSBundle mainBundle] pathForResource:[_filePath_ lastPathComponent] ofType:nil inDirectory:[_filePath_ stringByDeletingLastPathComponent]]

    in the following way:
    NSLog(@”With define %@”, BUNDLE_FULL_PATH(@”/temp/tempDir/tempFile.txt”));

    I get: 2010-08-29 12:50:26.489 ___PROJECTNAME___[3414:207] With define (null)

    While doing the following:
    [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:fileName];

    as used in:
    NSLog(@”With default method %@”, [SysTools pathBundle:@"/temp/tempDir/tempFile.txt"]);

    I get:
    2010-08-29 12:50:26.490 ___PROJECTNAME___[3414:207] With default method /Users/Panajev/Library/Application Support/iPhone Simulator/4.0.2/Applications/7CD5DB2E-7F87-41A8-B692-A44E548BB4F1/___PROJECTNAME___.app/temp/tempDir/tempFile.txt

  5. Matt says:

    Hmm. I never use leading slashes for paths since they’re always relative to the root, so that’s never been an issue, but I think you’re right that that’s a better and simpler way of getting the full path. Thanks :)

  6. Pingback: Games from Within | Games, Resources, And XCode

  7. Collin Allen says:

    Holy crap, I didn’t know Xcode could do that! Thank you thank you thank you!

  8. Pingback: Universal applications asset naming conventions, directory structure and macros | Karnak Games

  9. chris price says:

    problem with pathForResource? What about the common occurence
    of same named files in separate directories?

  10. Was just googling for whether UIImage imageNamed supports folders in the resource bundle. Now I don’t have to experiment to find out, thanks Matt!

  11. Mark says:

    Thanks! This was really helpful, I had multiple folders with same named resources and couldn’t find a way to choose which exact resource to load.

Leave a Reply

Your email address will not be published. Required fields are marked *


You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>