Using Compiler Variables in Swift

Using compiler variables in Swift

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.

Xcode: how to compile environment variables and refer to them in Swift?

You can do a pre-action script in Xcode build section
Xcode pre-action build

Which will modify placeholder with the following code:

let apiKey : String = "<# THE_API_KEY #>"

Modify the code directly in the source file

Before each build.

And you can add another one if you have a production key in the Archive pre-action

Exemple

place the apiKey variable in the file you want to access it

In Pre-action do a script to remplace a place holder text like THE_API_KEY

The script will look like this

 cat $PROJECT/$PATH_TO_FILE | sed 's/THE_API_KEY/YOUR_KEY' > $PROJECT/$PATH_TO_FILE

Don't forget to clean the code to avoid put the API key in you commit

With a Post-action

cat $PROJECT/$PATH_TO_FILE | sed 's/YOUR_KEY/THE_API_KEY' > $PROJECT/$PATH_TO_FILE

Swift: Using `var` leads to a compiler warning, using `let` leads to compiler errors?

Your

 public func push(_ newItems:[Item]) {

is a method of public class Stack<Item>, which is a reference type, therefore you can call it on a constant:

let s4: Stack = [1,2,3]
s4.push([4,5])

On the other hand, the variadic method

public mutating func push(_ items:Item...)

is an extension method of protocol CanStack, which can be adopted by structs as well, therefore it requires a variable. That is why

let s8 = Stack([4,5,6]) // init by array
s8.push(10, 11) // Error: Extra argument in call

does not compile.

Here is a shorter example demonstrating the problem:

protocol P {
mutating func foo()
mutating func bar()
}

extension P {
mutating func bar() {}
}

class C: P {
func foo() {}
}

let c = C()
c.foo()
c.bar() // Cannot use mutating member on immutable value: 'c' is a 'let' constant

The underlying reason (as I understand it from the sources listed below) is that a mutating func called on a reference type is not only allowed to mutate the properties of self, but also to replace self by a new value.

It would compile if P is declared as a class protocol instead (and the mutating keyword is removed):

protocol P: class {
func foo()
func bar()
}

extension P {
func bar() {}
}

Related resources:

  • Proposal: Intermediate mutation qualifier for protocol functions on reference-types in the Swift forum
  • SR-142 mutating function in protocol extension erroneously requires var declaration of class variables bug report.

declaring PHImageRequestOption variable in swift gives compiler error

Try below code as you are using swift:

let options = PHImageRequestOptions()


Related Topics



Leave a reply



Submit