Xcode, Folders and the File System – Part 2

In Part 1 of Xcode, Folders and the File System I walked through a short example on how to import folders into Xcode such that resources within a project have a folder structure that matches the file system.

In this post I will show you two ways to access the imported resources, one by specifying a path, one using an application bundle, both examples will focus on working with images. The code below is an example of building a path to a resource, avoiding a hardcoded path by using index values maintained within the application.

int modelIndex = 2, imageIndex = 5;
...
NSString *imageName = 
  [NSString stringWithFormat:@"/Model-%02d/coverflow/CoverFlow-%02d.jpg", 
   modelIndex, imageIndex];
NSLog(@"image: %@", imageName);

The output in the debug console looks as follows, notice the full path to the image:

2009-06-09 08:20:30.732 AppName[25154:20b] image: /Model-02/coverflow/CoverFlow-05.jpg

You can create a UIImageView referencing the file using the code shown below. The method imageNamed: looks for the image in the application’s main bundle if this is the first request for the image. If the image has been loaded previously, the image is retrieved from the system maintained internal cache.

UIImageView *wallpaper = 
  [[UIImageView alloc] initWithImage:[UIImage imageNamed:imageName]];

There are times when you will need to reference resources by working with the main application bundle. Following on the same theme of working with images, caching of images is not always a good idea (see the post Images and Caching for more information). In this case, using the method imageWithContentsOfFile: is a better option. However, there is one difference we need to account for when using this method, namely, imageWithContentsOfFile: loads image data from a specified path, however, it will not look in the application bundle by default.

Creating the proper path can be as simple as:

NSString *path = 
  [[NSBundle mainBundle] pathForResource:@"Splash" ofType:@"jpg" inDirectory:@""]; 
UIImageView *background = 
[[UIImageView alloc] initWithImage:[UIImage imageWithContentsOfFile:path]];

In order for imageWithContentsOfFile: to work with images imported from the file system as I demonstrated in Part 1, we need to specify the full path to the resource, here’s how that code might look:

NSString *dir = [NSString stringWithFormat:@"Model-%02d/coverflow", modelIndex];
NSString *file = [NSString stringWithFormat:@"CoverFlow-%02d", imageIndex]; 
NSString *path = [[NSBundle mainBundle] pathForResource:file
   ofType:@"jpg" inDirectory:dir];
UIImageView *wallpaper = [[UIImageView alloc] 
  initWithImage:[UIImage imageWithContentsOfFile:path]];

Working with files directly imported from the file system can be quite useful, even more so when there are many files to manage within an application. However, you will need to keep in mind how to access the resources, either through a full path or by working with an application bundle.

  1. I’ve been using this same approach for some time, but have been finding that as of late, I have to clean my builds before I can see the changes in resources managed like this. Have you come across this problem? If so, did you find a solution? I googled it and saw that it was an issue for older versions of XCode, but none of the solutions I saw for it worked for me….

  2. If you are referring to updating content within a folder (on the file system) and then having to do a “clean” for the changes to be recognized, yes, I’ve experienced the same. Seems the build system should be able to detect such changes…

    Any suggestions out there?

  3. Yes, thanks for clarifying what I meant… When I change a resource (eg a text file) on the file system, and do a build, it doesn’t show up in my app unless I do a “Build | Clean Target”, then a standard build. To work around it for the time being, I’ve been using some conditional code to look for the files on the local file system if I’m building for the iPhone simulator, and look for them in the resources if I’m not, since alot of the time I’m working using the simulator, this works pretty good….But having it work as it should for both device and simulator builds would be great…

  4. There is a way to overcame it – add a run shell script as the first build phase which touches all of your resource folders, which then xcode founds out as updated and copies them to the application package bundle again within every build:
    http://majicjungle.com/blog/?p=123

Comments are closed.