9

In Objective-C I had a bunch of compiler flags set in Build Settings -> Other C Flags that were being used in the code. For instance:

Flag => -DPortNumber = 1

And in code I was able to access it by @(PortNumber)

This doesn't work in Swift, and I'm not able to find an answer.

jscs
  • 63,694
  • 13
  • 151
  • 195
aryaxt
  • 76,198
  • 92
  • 293
  • 442

1 Answers1

16

The -D flag to C compilers defines a preprocessor macro. There are no preprocessor macros in Swift. So if you're looking to do something like:

// compile with -DPORT_NUMBER 31337
var port = PORT_NUMBER    // error

... you can't. Swift is designed for source code to be syntactically complete before compilation. If you could switch out blocks of it at build time, you'd break the ability of the toolchain to help verify that your code is correct. (Partly this is because preprocessor macros in C are textual replacement: you can use them to rewrite any part of the language, not just fill in values for variables.)

The Swift compiler does have a -D flag, but its use is more limited: you can use it for build configurations only. So, if you wanted to do something like the following, you'd be cool:

// compile with -DUSE_STAGING_SERVER
#if USE_STAGING_SERVER
var port = 31337
#else
var port = 80
#endif

Note that unlike C, everything inside an #if block needs to be syntactically complete. (For example, you can't put just the declaration line of a func in an #if block and leave the function body outside the conditional.)

Of course, this doesn't help you if you want to have a configuration value set at compile time be used in your code. For that, I'd recommend alternate approaches. Xcode can still do textual substitution in resource files, like property lists. (Note that the Info.plist that comes with your app is full of things like $(TARGET_NAME), for example.) So, you could include a bundle resource with your app whose contents are populated at compile time according to your project settings, then read your port number from that.

rickster
  • 124,678
  • 26
  • 272
  • 326
  • So is it possible to have a User defined value passed by a CI like "MY_VALUE" which would be referenced in the .plist and can be read from Swift? – Fawkes Oct 02 '18 at 16:02
  • Right — if you have something like `someKey = $(MY_VALUE)` (well, but in XML) in a plist, the build system will fill in MY_VALUE. (Look at the Info.plist that comes with your template project — some of the things like bundle name are defined that way.) Then Swift code that loads values from the plist will get the build-system-defined values. – rickster Oct 02 '18 at 18:07