Resource code generator for iOS inspired by Android resource handling
Objective-C
Switch branches/tags
Nothing to show
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
homebrew
rgen.xcodeproj
rgen
.gitignore
README.markdown

README.markdown

rgen

Resource code generator for iOS inspired by the Android R resource class.

The Android R resource class is generated by a tool called aapt (Android Asset Packaging Tool) and makes it possible to access resources conveniently and safely. For example access images like this imageView.setImageResource(R.drawable.someimage) or strings this getString(R.string.hello). rgen makes it possible to access resources in a similar way on iOS by reading the Xcode project file and generate code for resources that will be available in the application bundle.

Load images like this

imageView.image = I.images.cuteSeal;

instead of this

imageView.image = [UIImage imageNamed:@"images/cute-seal.png"];

Specify resource paths like this

[NSDictionary dictionaryWithContentsOfFile:P.files.dogsPlist];

instead of this

[NSDictionary dictionaryWithContentsOfFile:
 [[[NSBundle mainBundle] resourcePath]
  stringByAppendingPathComponent:@"files/dogs.plist"]];

Name localization string keys like this

NSLocalizedString(S.cats, nil)

instead of this

NSLocalizedString(@"cats", nil)

This is very nice for several reasons

  • Less error-prone as you get compile time errors for missing images, files and string keys.
  • Code completion for resources
  • Less and nicer looking code

Install

Homebrew:

$ brew install --HEAD https://raw.github.com/wader/rgen/master/homebrew/rgen.rb

Compile from source:

$ git clone git://github.com/wader/rgen.git
$ cd rgen
$ xcodebuild
$ cp build/Release/rgen /to/somewhere

Note that if you compile with Xcode 4 from the IDE the binary will probably not end up in the build directory. Instead try "Show in finder" on the rgen binary under "Products".

If don't want to compile yourself there is a binary for download compiled for Mac OS X 10.6 i386 that will work on both 32 and 64 bit systems.

Usage

Usage: ./rgen [-IPSv] xcodeproject [Output path] [Target name]
  -I, --images      Generate I images property tree
  -P, --paths       Generate P paths property tree
  -S, --stringkeys  Generate S localizable string keys class
  --loadimages      Generate loadImages/releaseImages methods
  --ipad            Support @ipad image name scale suffix
  --ipad2x          Support @2x as 1.0 scale image on iPad
  -v, --verbose     Verbose output

If no Output path is specified code will be generated to Resources.m and Resources.h in the current dirctory.

If no Target name is specified rgen will merge resources for all targets.

-I, -P and -S enables code generation for the different resources. At least one must be enabled.

--imageimages generates two methods loadImages and releaseImages for each image directory. loadimages can be used to load and retin all images in a dirctory and below. releaseImages does the opposite by releasing them.

--ipad generates image loading code that will extend the normal @2x suffix to also load @ipad images if found on iPad devices.

--ipad2x generates image loading code that loads @2x images as scale 1.0 images on iPad devices. If --ipad is enabled a @ipad image has priority.

-v enables verbose logging to see what rgen does.

Xcode build run script

Add a "New run script build phase" to your target. The run script should look something like the one below. which is used to make sure a user can build without rgen is installed. $PROJECT_FILE_PATH and $SRCROOT will be assigned by Xcode.

RGEN="/path/to/rgen"
which -s "$RGEN" && "$RGEN" -IPS "$PROJECT_FILE_PATH" "$SRCROOT/Classes/Resources"

Now build the target and two new files, in this case Classes/Resources.m and Classes/Resources.h will be created. Add these as source files to your project and then import Resources.h where you want access to the resouces classes. Then and your good to go!

To make thing even smoother you can add a #import "Resources.h" line to your *_Prefix.pch file. rgen makes sure not to touch the generated files if nothing has changed since last run to not trigger unnecessary rebuilds.

Multi target setup

Every target should generate their own resource code and header file to make sure you get compile errors if you accidently use resources not available to a target.

Each target should have a build script, for example:

TargetA

RGEN="/Users/mattias/src/rgen/build/Release/rgen"
which -s "$RGEN" && "$RGEN" -IPS "$PROJECT_FILE_PATH" "$SRCROOT/Classes/TargetA" "$TARGET_NAME"

TargetB

RGEN="/Users/mattias/src/rgen/build/Release/rgen"
which -s "$RGEN" && "$RGEN" -IPS "$PROJECT_FILE_PATH" "$SRCROOT/Classes/TargetB" "$TARGET_NAME"

Now the files TargetA.m, TargetA.m, TargetB.m and TargetB.h will be generated. Build each target and then add the files to the corresponding target of your project.

Unfortunately the C preprocessor does not support comparing strings (#if TARGET_NAME == "TargetA" etc) so if you not already have some define to distinguish between your targets you should add a define under "Preprocessor marcos" in your build settings. A solution is to define TARGETA to some dummy value for target TargetA and TARGETB for target TargetB.

Now add imports to some shared header file (*_Prefix.pch is a good place).

#if defined(TARGETA)
#import "TargetA.h"
#elif defined(TARGETB)
#import "TargetB.h"
#endif

Done!

Run from terminal

Should work fine as long as your project does not have unsupported source trees paths. rgen uses various exported environment variables when running in a build script to figure out paths but can fallback to guessing paths based on project path.

Example: rgen -IPS path/to/app.xcodeproj path/to/Classes/ResourcesTargetA TargetA

Will generate files path/to/Classes/ResourcesTargetA.m and path/to/Classes/ResourcesTargetA.h with images, paths and string keys found for target TargetA

Known issues and TODOs

  • Support custome source tree paths
  • Support Mac OS X applications. Autodetect via SDK (iphoneos/macosx) and generate NSImage code etc
  • Read other .strings files (more then just Localizable.strings)
  • Detect class name collisions
  • Support document paths somehow. Specify list of known paths etc
  • Rebuild dependencies seams to be calculated before starting build so you might need to build twice to use updated resources files
  • Xcode plugin?
  • RGEN path as user setting for shared project files. Make sure rgen is in path or use .xcconfig files?