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.
This results in the following constants being generated:
1 2 3 4 5 6 |
|
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.