Virtually all programming languages include the ability for programmers to store values in memory using an associated name chosen by the programmer. Variables
allow programs to operate on data values that change during the run of the program.
Variables Versus Constants
You may
want to
store a named value in your program that will not change during the life of the program. In the previous example, the value of Pi should never change during the course of a program. How can we ensure that, once defined, this named value can never be accidentally changed by our code?
Swift
variables are
declared using the var keyword, while Swift
constants are declared using the let keyword, for example:
In this code, the named value pi1 is a variable, and its value can be changed by the code after it is declared. The following line of code later in the program would be legal, even though it would result in an invalid value for pi1:
On the other hand, since pi2 was declared as a constant, using the let keyword, the following line of code later in the program would result in a compile-time error, since changing a let constant is illegal:
Generally, any time you create a named value that will never be changed during the run of your program, you should use the let keyword to create a constant. The Swift compiler enforces this recommendation by creating a compile-time warning whenever a var is created that is not subsequently changed.
Note
Other than the restriction on mutating the value of a constant once declared (for safety), Swift variables and constants are used in virtually identical ways, and you usually won't think about whether a symbol is a variable or a constant after declaring it.
In the
previous example, we created the variable pi1 without specifying its data type. We took advantage of a Swift compiler feature called type inference.
When you assign
the value of a variable or constant as you create it, the Swift compiler will analyze the right-hand side of the
assignment,
infer the data type, and assign that data type to the variable or constant you're creating. For example, in the following declaration, the compiler will create the variable name as a String data type:
As a
type-safe language, once
a data type is inferred by the compiler, it remains fixed for the life of the variable or constant. Attempting to assign a non-string value to the name variable declared above would result in a compile-time error:
While Swift is a
type-safe language, where variable types are explicit and do not change, it is possible to
create Swift code that behaves like a dynamic type language using the Swift Any data type. For example, the following code is legal in Swift:
While this is
legal, it's not a good Swift programming practice. The Any type is mainly provided to allow bridging between Objective-C and Swift code. To keep your code as safe and error-free as possible, you should use explicit types wherever possible.
Swift variables
and constants have the same naming rules as most C-inspired programming languages:
Must not start with a digit
After the first character, digits are allowed
Can begin with and include an underscore character
Symbol names are case sensitive
Reserved language keywords may be used as variable names if enclosed in backticks (for example, `Int`:Int = 5)
When
creating variable and constant names in Swift, the generally accepted naming convention is to use a camelCase naming convention, beginning with a lowercase letter. Following generally accepted naming conventions makes code easier for others to read and understand (https://swift.org/documentation/api-design-guidelines/#follow-case-conventions).
For example, the following would be a conventional variable declaration:
However, the following would not be conventional, and would be considered incorrect by many other Swift developers:
Unlike
many other programming languages, Swift is not restricted to the Western alphabet for its variable name characters. You may use any Unicode character as part of your variable declarations. The following variable declarations are legal in Swift:
Note
Just
because you can use any Unicode character within a variable name, and can use reserved words as variables when enclosed in backticks, it doesn't mean you should. Always consider other developers who may need to read and maintain your code in the future. The priority for variable names is that they should make code easier to read, understand, and maintain.
In this section, you'll use an Xcode playground to create a variable and constant, and observe the difference between them. So, let's get started.
To work with variables, follow these steps:
Launch Xcode as before, and create a new playground named Create a Variable.playground.
Add the following code to the playground to create a constant (that is, an immutable variable) named name, and a variable named address:
In this code, both name and address store string text in named memory locations. And we can include them both in the print statement in the same way.
Now add the following code to change John Doe's address and print the new information to the console:
In the console output, the address is changed as expected.
Finally, let's try to change the string stored in the name variable:
In this case, the Swift compiler generates a compile-time error:
By declaring name as an immutable variable with let, we let the compiler know no code
should be allowed to change the content of the variable after its value is initially set.
One of Swift's
unique language features is its inclusion of tuples. By default, variables and constants store a single value. Tuples allow a variable or constant name to refer to a set of values. While tuples do not exist in many languages, you can think of them as
compound values, and they function almost identically to a
structure, which is a single named object which can store more than one variable embedded within it.
By using a tuple, we could take the following variable declaration:
We could combine it to the following:
Then we can access the individual members of the tuple as follows:
Tuple members can also be given individual names, as follows:
Swift
functions can accept multiple input parameters, but return only one value. A common use case for a tuple variable type is to include more than one value from a function:
A second way to return multiple values from a function is to use inout parameters, which allows a function to change the value of an input parameter within that function.
While there are valid use cases for changing inout parameter values, returning a tuple has the advantage of returning a value type—rather than modifying input values.
Note
Tuples behave
much like structures—which are predefined compound data types in Swift and many other languages. You may be tempted to use tuples rather than making the extra effort to create structures since they provide similar utility. Be careful not to overuse tuples. They are convenient for ad hoc, lightweight composite data types, but when used in complex programming, use cases can result in code that's more difficult to understand and harder to maintain. Use tuples as they're intended, as a means to bundle a few related components of a data element.
Let's look at creating a tuple. We'll use an Xcode playground to create and use a tuple. Here are the steps:
Launch Xcode as before, and create a new playground named Create a Tuple.playground.
Add the following code to the playground to create a tuple containing a person's name, address and age:
This code is very similar to the previous , except that we've used a tuple to group together values describing John Doe—rather than using separate variables for each element.
While this syntax is legal, acceptable, and common, it can begin to result in difficult to understand and maintain code—especially when a tuple contains more than two simple values. To make a tuple more maintainable, you can give variable names to each of its components.
Add the following to the playground:
In this
second approach, each member of the tuple has a descriptive name, making it easier for the reader of the program to understand and maintain the code.
Another
unique language feature Swift provides is the optional. In most programming languages, all variables and constants
must hold some value. But, in the real world, sometimes a value is
unknown. For example, an
address may or may not contain a second address line, and more than 60 countries in the world don't use postal codes. Optionals allow variables to indicate whether their value is missing (that is, not assigned), or is truly a
blank value.
Note
When variables are declared optional in Swift, they behave very similarly to column values in SQL database such as Oracle, SQL Server, and MySQL.
Optionality for Swift variables is
optional (pun intended). To declare a variable as an optional, add a question mark (?) to the end of its data type (or assign another optional variable's value to it so the optional property is inferred from the existing variable).
The following variable name
is not an optional:
This next variable name
is an optional, and has an initial
value of nil:
The presence of the question mark intuitively expresses that the variable may—or may not—contain a string. If the optional is not assigned a value, it will automatically
be set to nil, meaning it has no value.
Earlier in
this lesson, we declared variables with initial values assigned. These variables are
not optional, have a value, and can never be assigned a nil value, or an unwrapped optional variable's value.
In this section, we define a variable as an optional by adding a question mark to the type name, which makes it subject to the Swift compiler's optional validation rules.
A third possibility
is to declare a force unwrapped variable—a variable that can be nil, but is not optional. This type of variable is declared by placing an exclamation point (!) after the type (rather than the question mark (?) for the optional), for example:
When a variable is declared in this fashion, the compiler
will allow the variable to be assigned a nil value at any time, but
will not warn the programmer at
compile time when the variable's value is (or could be) assigned a nil value.
There are limited circumstances where this technique is required, and in general it should be avoided.
Note
Why don't we make all variables optional? Optional is a powerful Swift feature, but working with optional variables requires more code as they are used, primarily to check for nil values before accessing the optional value. In general, you should use optional variables when variables may be missing values, but not use optional variables when you know a variable will always have a value.
As mentioned, the
simplest way to declare a variable as an optional is to append the data type with a question mark, for example:
Because of Swift's type inference, the following line of code
will create a second variable of optional type:
The syntax to assign a value to this variable is the same as it would be if the variable was not declared as optional:
The difference between optional and non-optional variables is primarily when you access the value of an optional, which we'll cover next.
Optional variables
in Swift can be directly compared to the absence of value (nil) and assigned a nil value. For example, in the following two statements, variable a initially has a value of 4, then is assigned a nil value, and then is checked for having a nil value:
While the presence or absence of a value within an optional can be directly tested, extracting and using the value contained within an optional requires that the optional (the envelope) be unwrapped, and the content (value) extracted. We'll learn how to do this next.
Accessing Optional Values
Think of an
optional as a value
wrapped in an envelope. You cannot access the contents of an envelope without opening it (unwrapping it), and then removing the contents.
You can primarily unwrap an optional and use its value in two ways:
Force unwrap
Conditional unwrap
We'll learn each of these techniques next.
Force Unwrapping an Optional
Look at the
two optional
Int
variables:
You could attempt to assign a to b, for example:
But this would result in a compile-time error:
As the
error indicates, accessing the value of an unwrapped optional variable is (always) illegal. One approach to solving this problem is to force unwrap the variable as we use it. To force unwrap a variable, simply place an exclamation mark (!) after the variable name, for example:
Force unwrapping is similar to
using a type cast in many languages. In Swift, a force unwrap tells the compiler to assume that the optional contains a value.
However, a force unwrap shifts all the responsibility to the programmer for ensuring optionals actually have values. The above example, b = a!, would allow the code to compile, but would generate the following runtime error, and the application will crash:
Because variable a is an
optional with no value, there is no value to extract from it to assign to b.
Note
Force unwrapping should not be viewed as a way to
get around compiler type-safety features. Only use force unwrapping when you're absolutely certain that it's impossible for an optional variable to contain a nil value. In the following code, a force unwrap would be acceptable:
Conditionally Unwrapping Optionals
While there are
times when force unwrapping variables is safe, you should typically take advantage of Swift's type-safety features by using conditional unwrapping.
With
conditional unwrapping, we ask the compiler to first check whether the optional has a value, and return the value if present, or nil if not.
For example, to assign the value of optional a to a new, non-optional variable b, we can use the following code:
This code snippet would print the value 4 to the console. If we had not assigned the initial value 4 to a, then nothing would have been printed.
Use an Xcode playground to create and use an optional, by performing the following steps:
Launch Xcode as before, and create a new playground named Using Optionals.playground.
Add the following code to the playground to create an optional containing a person's name:
Now add the following code to check whether the optional is nil:
Of course, since we assigned the value nil, it is nil.
A more common way to check for a non-nil optional is to use the if/let syntax covered previously.
Add the following code to assign a value to the optional content, then print it to the console:
Because
you assigned a value to the variable name, the string John Doe is printed to the console.
Finally, comment out the variable
assignment. The output will now change to the name is still nil, because the if/let syntax detected that the variable name contains no value.
The Swift guard Statement
It's very
common that Swift functions should only execute when parameters passed to them are in an expected state. In early versions of Swift, the conditional unwrapping technique was often used to provide this type of safety checking. For example, a function that accepts an optional
Int
value, but should only proceed when the parameter is not nil might look as follows:
While this function is only a few lines of code, imagine if the work done on the unwrapped variable was more complex. To allow parameter and other data state checking to be concisely done at the beginning of functions, Swift includes a guard keyword.
The following is a version of doubleValue that uses the guard syntax to place data state checks at the top of the function:
This is the end
of this section. Here, we have had a deep look at how to declare variables and constants in Swift. We also worked with tuples and optionals.