Joris Kluivers

I like to build software.

Generating Constants for Storyboard Identifiers

After I mistyped yet another segue identifier string this week my application once again suffered from a familiar crash:

Receiver (<JBWMasterViewController: 0x8cbd540>) has no segue with identifier 'showDetial'

You have probably seen a similar crash yourself, caused by a call to -[UIViewController performSegueWithIdentifier:sender:] with an unknown identifier. To prevent having hard-coded strings repeated all over the place I was already using constants to refer to my identifiers. However maintaining these constants manually is still prone to errors such as small typo’s. As demonstrated by my crash mentioned above.

To finally rule out crashes like this from now on my projects use a small python script to generate NSString constants for all identifiers found in UIStoryboard files.

Example usage

An example project is available on github that shows the script in action. The projects storyboard has two controllers and a single segue connecting them. Both controllers and the segue have an identifier set in the inspector.

Storyboard example

This results in the following constants being generated:

1
2
3
4
5
6
/* Segue identifier constants */
extern NSString * const JBWShowDetailIdentifier;

/* Controller identifier constants */
extern NSString * const JBWDetailViewControllerIdentifier;
extern NSString * const JBWMasterViewControllerIdentifier;

The identifier prefix is customizable of course. Import the header file when needed and you’re good to go. Each time you modify a storyboard file your identifier constants will be generated automatically, providing you with:

  • compile time checks for any storyboard identifier
  • code completion (no need to remember the actual identifier)

Project setup

To make this work the python script is setup as a Run script build phase for the main project target.

The python file itself is stored in a Scripts directory. The generated files are placed in a generated directory next to the regular source files. I also commit the generated files to git.

Paths for the storyboard files and generated code are specified as input and output files for the build phase. This enables Xcode to figure out dependencies and will run the script only when the storyboard files have actually changed.

For a regular project generated from an Xcode template my projects use the following directory layout.

Project/
    Scripts/
        - generate_constants.py
    TargetName/
        generated/
            [header / implementation]
        Base.lproj/
            Main.storyboard
            Main_iPad.storyboard

The script will work with different directory layouts, just make sure you modify the paths used in the build phase.