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")]; // //
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.