Some Fundamentals - FUNDAMENTALS - Understanding Swift Programming: Swift 2 (2015)

Understanding Swift Programming: Swift 2 (2015)

PART 1: FUNDAMENTALS

2. Some Fundamentals

This chapter describes some rather miscellaneous but important aspects of Swift that you should know early on. This includes what names are allowed for variables and constants, Swift not usually needing semicolons, comment syntax, printing, string interpolation, assertions and errors, the scope of variables, range operators, underscore (_) characters, and checking the availability of specific iOS (or Mac) APIs. These are aspects of Swift that are often different for Swift than for other programming languages.

Variable and Constant Names

Names for variables and constants can include letters of the alphabet and numbers, although they cannot begin with a number. They can include any public Unicode character. Logographic characters such as those in Chinese and Japanese are allowed, as are emoji characters. (See Chapter 7 for a discussion of Unicode.) The following are all valid names:

var a = 5

var b378 = 378

var = "Hamburger"

var 的 = "Chinese"

var 絵 = "Japanese"

Names cannot contain whitespace characters and cannot contain symbols unless those symbols represent valid Unicode characters. The following are not valid names

var 378a = 378 // Not Valid, begins with a number

var error Code = 345 // Not Valid, contains whitespace

Once you’ve declared a constant or variable of a certain type, you can’t redeclare it again with the same name, or change it to store values of a different type.

Semicolons and Multiple Statements on a Line

Swift does not require a semicolon at the end of a statement, although you can use one if you like:

var m = 78 // Usual practice

var m = 78; // Allowed

Multiple statements can be placed on a single line, but semicolons are then required to separate the statements:

var m = 78; var p = 8.9; var r = "hey"

Note that there is no semicolon at the end of the line. Semicolons are statement separators in Swift, and are not required at the end of the line although, again, they are allowed:

var m = 78; var p = 8.9; var r = "hey";

Comments

As in most C-like languages, the compiler will ignore text to the right of a "//" sequence on a line:

// This is a comment, please ignore it Mr. Compiler

Similarly, the compiler will ignore text between /* and */ sequences, either on one line or across multiple lines.

/* This text will be ignored */

/* And also this text and the text on the line below it,

including this text */

An unusual aspect of Swift is that it allows nested /* */ comments:

/*

x = 37;

/* this is an important parameter and if it is wrong it might cause a crash */

*/

The idea here is that you sometimes want to use a /* */ sequence to comment out a block of code to see if, say, the crash you are getting goes away. But in most languages, if you have already embedded comments in the block using /* */ you can't do this. In Swift you can.

Printing

You can "print" a string or a variable with print. There are two versions of it. The most commonly used version has a single parameter consisting of a string to be printed. This prints the string and follows it with a newline character. (In other words, the statement prints the string and moves the cursor to the beginning of the next line.)

The code is:

print ("You got here in your program")

// Prints: You got here in your program

The alternative version has two parameters. The first parameter contains the string to be printed, while the second parameter is a Boolean that indicates whether the string should be followed by a newline (true) or not (false).

var m = 78

print (m,appendNewline: true)

// Prints: 78\n (78 followed by newline character)

print(m, appendNewline: false)

print(m, appendNewline: false)

// Prints: 7878

Note that "print" here usually means "display on the console log".

(This is a change from Swift 1. In Swift 1, there were two print statements: print, and println. The print statement printed a value with no newline character appended. The println statement printed a value with a newline character appended.)

String Interpolation

You can insert values from constants and variables into strings with string interpolation. This is particularly useful with the print statement discussed above.

In string interpolation, the name of a variable or constant is placed within a string and surrounded by parentheses, with a backslash just before the left parenthesis.

var m = 78

var s = "This is an ordinary string with an embedded value of \(m)"

print(s)

// Prints: This is an ordinary string with an embedded value of 78

More commonly, the printing would be done directly:

print("This is an ordinary string \(m)")

Assertions

An assertion is a runtime check to determine whether a particular condition is true. If the condition is NOT true, the execution of the program halts with a runtime error and a message is printed (displayed) on the console log.

The keyword assert is used, along with two parameters: a conditional expression and a string to be displayed as a message should the condition be false. Thus:

x = 5

assert (x > 6, "x must be greater than 6")

// Will halt with runtime error

In this example the variable x is set to 5, but the assertion conditional expression is x > 6, meaning that the normal expectation is that x will be greater than 6. Since the program fails this test, the program will halt and the message "assertion failed: x must be greater than 6" will be printed out on the console log.

Error Handling—New in Swift 2

Swift has (new in Swift 2) a sophisticated error handling system that is similar to, but in some ways different from, the try-catch approach used in many other languages.

See Chapter 21, “Error Handling”, for details.

Scoping of Variables

Whenever a variable is declared it is done so in a particular scope, meaning a location where that variable is known and can be used.

Consider the variables in the following code:

var n = 5

if x == 0 {

var p = 7

}

And let's assume that this code is in the global space in a Swift file—-it is not in a class, function, or the like.

The variable n is defined at global scope. If we added a couple of print lines to the code above, as follows, what would happen?

var n = 5

if x == 0 {

var p = 7

print(n) // Prints: 5

}

print(n) // Prints: 5

Both would work. The variable n works both in the global scope it was defined in and in the narrower scope of the if clause.

However, suppose we attempt to print the value of p in the same way:

var n = 5

if x == 0 {

var p = 7

print(p) // Prints: 7

}

print(p) // Error

The first print line would work, but the second will blow up. Why? It's because the variable p was created in the scope of the if clause. It exists only in that scope, and an attempt to access it outside of that scope will fail.

Range Operators

Swift has what are known as range operators, that allow referring to a range of items rather than a specific item.

A closed range operator has a syntax like 1. . .7. With a closed range operator, we can define a range that runs, for example, from 1 to 7 as follows:

for k in 1...7 {

print("k is \(k)")

}

A half-open range operator works similarly, but does not include the ending value. The following example iterates 6 times, rather than the 7 in the example above:

for k in 1..<7 {

print("k is \(k)")

}

Underscore Character

An underscore (_), also known as a wildcard, is used in Swift in a number of different situations. The commonality across these situations is that a variable or constant that is normally used in that situation isn't actually needed, and the underscore is used instead.

For example, a certain kind of for-loop can iterate through an array using code like this:

for k in cities {

print("One iteration")

}

In this particular situation the variable k isn't actually needed for anything beyond being a sort of placeholder in the for loop, and an underscore character alone can work just as well:

for _ in cities {

print("One iteration")

}

Underscores are also used to indicate that an expected input parameter in a method call is not necessary, and in switch statement matching of tuples to indicate that any value will match for that particular position. Details of how this is done are provided in Chapter 20, "The Flow of Control Revisited".

Aliases for Types

An alias for a type can be defined using the typealias keyword, allowing the type to be referred to in a more easily understood way. For example, the following code creates a type alias for three different levels of speech quality, depending upon how many bits are used to represent it:

typealias excellentQualitySpeech = UInt32

typealias goodQualitySpeech = UInt16

typealias marginalQualitySpeech = UInt8

A programmer can then just refer to one of the quality levels:

var speechSample: goodQualitySpeech

This has a couple of advantages. First, it's easier to remember, to document, and to communicate with others that one chose the "good" quality speech option. And second, it makes it easier to change. You may end up with a program with a lot of references to "goodQualitySpeech", but decide that that speech isn't good enough quality, or is taking too much memory. You can then change the typealias to a different integer type, either to experiment, or permanently. You can do this once rather than having to change multiple references.

typealias Byte = UInt8

will allow the type UInt8 to be referred to by the alias Byte, as in the following:

var byteCoding: Byte = 354

This explicitly sets the type of the variable byteCoding to UInt8, which may be a more obvious way to indicate why you are choosing that integer length.

Checking API Availability

New in Swift 2 is a capability for checking the availability of an API (e.g., in Cocoa Touch) before executing code making use of it.

There are two parts to this capability. The first part is in Xcode. Xcode will give you a warning if you attempt to use an API that is only available in an iOS version that is newer than your defined target platform. (When you create an app project in Xcode you must define a “Deployment Target”, which is the version of iOS that is the earliest (“oldest”, “minimum”) that you will allow your app to run on. This might be, for example, 8.1 or 7.1.)

Suppose that you are building an app and want to make use of an API that is only available in iOS 9. However, you set your deployment target to iOS 8 so that devices that have not yet installed iOS 9 can use your app. If you have code that uses an API that is only contained in iOS 9, however, Xcode will warn you that you need to do something about the problem.

The second part of the availability capability is seen when the app runs. You can use an if-else statement to check to see if a particular API is available on the platform the app is running on. If it is available, your code for that API runs. If it is not available, code contained in the else clause runs.

For example, you may want to use a new API in iOS 9. But if it is not available on a particular device, you can use a less-desirable, but still workable API for the version of iOS that the device is running. The code is:

if #available(iOS 9, *) {

// code to use the iOS 9 API goes here

}

else {

// code to use a previous iOS version API goes here

}

The #available condition takes as parameters the names of operating systems and versions. If more than one is specified, they are separated by commas. (A Mac OS might be specified by OS X 10.10). Both general version numbers (e.g., iOS 9) and specific versions (e.g., iOS 9.01) can be specified.

The asterisk (“*”) used as the last argument is required. This is looking ahead for when the code might be run on a different operating system, such as the Apple Watch operating system. What the asterisk says is that on that different operating system, the code in the main block (if statement) will be run if the version of that operating system is at or after the earliest (that is, “minimum”) deployment target set for that operating system.

Hands-On Exercises

Go to the following web address with a Macintosh or Windows PC to do the Hands-On Exercises.

For Chapter 2 exercises, go to

understandingswiftprogramming.com/2