I’ve previously written about using enumerations in Swift to encapsulate special values that could end up falling into the “magic string” category if they were to simply be scattered in-line throughout your code. The primary example I proposed for such a “magic string” replacement was Storyboard Segue Identifiers. These special identifiers have such a specific purpose that felt to me like a natural fit to create a Type in the form of an enumeration (which I called SegueIdentifier) to group them all together in one place so that I could easily find them and modify them, should I ever need to do so.
I still like that solution for groups of things, but it’s a lot of “ceremony” to use enumerations for encapsulating everything that may have been implemented as a macro expression or a static global constant in Objective-C.
I ran across this in the Swift developer documentation that I think will be of help to folks who want to avoid “magic values” throughout their code, but don’t want to employ enumerations where they’re not the best fit. Here’s a snippet:
So there you have it, folks! One easy alternative to your former #define habits when you’re working in Swift is to simply declare a constant (using the let keyword) instead. The word “constant” is key – the last thing you want to do is declare a variable in some global scope (using the var keyword) where the value of the identifier could be changed somehow, if even by accident.
Organizing #define Replacement Constants
The question that naturally comes next is, “Where do I declare a constant that I’m using to replace a #define?”
The answer is not black and white – a few factors play into your decision of where to declare them.
In general, I would probably declare such a constant in the location that’s closest to the context in which it is used. Here are a few examples to consider:
- If it’s only going to be used in a single function, it’s reasonable to declare the constant locally at the top of that function, or anywhere near where it will be used.
- If it’s only used in a single class/struct, perhaps declaring it at the top of that class/struct is a good idea.
- If it’s going to be a value that’s used in multiple classes/structs, it may be time to create a new .swift file and place it there so that you can find it again.
- Start with a very small scope, and as that constant broadens in its usage throughout your project, gradually move it to more and more globally visible locations.
Using a globally-defined constant is exactly what I did for checking the iOS version number of a user’s device. I simply created a new file called “iOSVersions.swift”, placed my global constant definitions in it, and was able to reference those constant names everywhere in my project that I needed to perform conditional logic based on the iOS version number.
A simple Swift alternative to a #define macro in Objective-C it to define a constant at a scope that’s appropriate for where you plan to use that constant.