3 min read

Handling Developer-Specific Constants in iOS

Handling Developer-Specific Constants in iOS
Special thanks to Jeff Lutzenberger, Ph.D., for writing today's blog post. You can connect with him on LinkedIn.  
 
 
FROM THE EDITOR:
 
Coders. Developers. Engineers. Programmers. Who are they? What do they do? It’s almost like magic. Kinda like the Wizard behind the curtain. But at Pulsara, it’s different. We are all on the same team with the sole focus of simplifying health care in the moments when time is critical.
 
Healthcare clinicians speak their own language. In the same way, so do developers. This post is written by one of our own developers. Yes, it’s technical. Just like medical acronyms like STEMI and RACE come from a complicated background. But for those coders out there that are interested in making a different in the world, check it out. It’ll provide you an insight into how we look at the mobile healthcare community.
 
 
Xcode Run Scripts are Neat.  
 
 
In our iOS project we define a handful of build target-specific constants, which we handle with #ifdefs in header files. We also have some constants in our development build that are specific to a developer’s machine and/or location. Since these constants change often, we don’t really want to track their changes in our repo. A common solution to this problem in many languages is to use untracked configuration files. With this approach .template files are used to store default values. During a build step, templates are copied to the actual files referenced by the project. For example, SuperAwesomeConfigs.h.template would be copied to SuperAwesomeConfigs.h. We’ve taken this approach in our iOS project. And, while I’m sure there are better solutions, it certainly solves our problem today. Here’s how we do it.  
 
In our application we handle build target-specific constants in a super cleverly named header file called: PSRConstants.h. Inside this file we use preprocessor directives to set constants based on the build target. Like this:

#ifdef PRODUCTION_MODE

#define kPSRBeer @"Lager"

#elif STAGE_MODE

#define kPSRBeer @"APA"

#elif LOCAL_MODE  

#define kPSRBeer @"IPA"

#endif

This works ok, but what if I’m working in the LOCAL_MODE build target and I’m really more in the mood for a nice malty Bock. Of course, I can change #define kPSRBeer @"IPA" to #define kPSRBeer @"Bock" but then when I commit my work, my colleagues will be stuck with a Bock too. Knowing the fine folks I work with that just won’t do! Instead, I can include an untracked file containing my preferences, like this:

#ifdef PRODUCTION_MODE

#define kSSBeer @"Lager"

#elif STAGE_MODE

#define kSSBeer @"APA"

#elif LOCAL_MODE  

#importPSRLocalBeerChoice.h

#endif

And in PSRLocalBeerChoice.h I can do this:

#define kSSBeer @"Bock"

Boom! Malty Bocks all day long! As long as PSRLocalBeerChoice.h is added to the project, the compiler will include my personal beer preference when the build target is set to LOCAL_MODE, which means I’m one step closer to being able to build my project with a delicious Bock and the IPA aficionados will be none the wiser.

The next step is to make sure this file isn’t tracked by git, since I don’t want to accidentally include a switch to Bock in my next pull request. We can handle this by adding PSRLocalBeerChoice.h to our .gitignore file. That will prevent git from picking up any changes to PSRLocalBeerChoice.h. We still have another little problem. When we added PSRLocalBeerChoice.h to our project, Xcode started tracking it for us. We should remove it from the project’s git index. Let’s create a .template file, start tracking it and remove the original file:

$ cp <wherever your constants file is>/PSRLocalBeerChoice.h <wherever your constants file is>/PSRLocalBeerChoice.h.template

$ git add <wherever your constants file is>/PSRLocalBeerChoice.h.template  

$ git rm <wherever your constants file is>/PSRLocalBeerChoice.h

Now the original file will no longer be included in our repo, but Xcode still expects it to be there (because it’s still in our project.pbxproj). Wait! We’re not quite done. If someone clones our repo at this point, the build will fail because PSRLocalBeerChoice.h is missing. We could instruct developers to manually create the file; but my colleagues refuse to do anything manually that could easily be automated. We can do it automatically with our template file and a simple Run Script.

At this point, our PSRLocalBeerChoice.h.template should look like this:

#ifndef Pulsara_PSRLocalBeerChoice_h

#define Pulsara_PSRLocalBeerChoice_h

#define kPSRBeer @"IPA"

#endif

Let’s create a Run Script in Xcode that will copy the template file to the required header file if, and only if it doesn’t already exist. Here’s what our Run Script looks like:


Screen Shot 2015-04-06 at 9.06.57 PM.png

Note, the -n tells cp to copy if and only if the file does not exist. The part at the end allows the build script to succeed even when the file already exists. Now, when our repo is cloned and built for the first time, the template file is copied to PSRLocalBeerChoice.h and we’re free to change kPSRBeer to whatever the heck we’re in the mood for - as long as it’s not a sour beer, they’re just not appropriate for programming.

I’m sure there are better solutions to this problem, this is just the first one that came to mind and it seems to be working well so far. How have you solved this problem? We’d love to hear from you!

Meet our developers (and the rest of the team) And follow them on LinkedIn!

Arkansas EMS Org Improves Pediatric Behavioral Health Patient Care with Pulsara

Arkansas EMS Org Improves Pediatric Behavioral Health Patient Care with Pulsara

The mental health of America’s youth is under duress, and it didn’t start with COVID-19. It’s a problem that’s been a much longer time coming. In...

Read More >>
Modern MCI Response: How Texas is Solving the Crisis Communication Gap

Modern MCI Response: How Texas is Solving the Crisis Communication Gap

Imagine: In the midst of a pandemic, you're managing patient load across a state that covers over 261,000 square miles and is home to over 30 million...

Read More >>
Streamlining Crisis Response: A Deep Dive Into MCIs and Large Events

Streamlining Crisis Response: A Deep Dive Into MCIs and Large Events

Patient tracking during MCIs and pre-planned events is a complex operation with many moving parts. Every incident is different and requires different...

Read More >>