Swift 2 Data Types, Constants and Variables

From Techotopia
Revision as of 20:13, 27 October 2016 by Neil (Talk | contribs) (Text replacement - "<table border="0" cellspacing="0"> " to "<table border="0" cellspacing="0" width="100%">")

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search
PreviousTable of ContentsNext
An Introduction to Xcode 7 PlaygroundsSwift 2 Operators and Expressions


Learn SwiftUI and take your iOS Development to the Next Level
SwiftUI Essentials – iOS 16 Edition book is now available in Print ($39.99) and eBook ($29.99) editions. Learn more...

Buy Print Preview Book


Prior to the introduction of iOS 8, the stipulated programming language for the development of iOS applications was Objective-C. When Apple announced iOS 8, however, the company also introduced an alternative to Objective-C in the form of the new Swift programming language.

Due entirely to the popularity of iOS, Objective-C has become one of the most widely used programming languages today. With origins firmly rooted in the 40 year-old C Programming Language, however, and in spite of recent efforts to modernize some aspects of the language syntax, Objective-C was beginning to show its age.

Swift, on the other hand, is an entirely new programming language designed specifically to make programming easier, faster and less prone to programmer error. Starting with a clean slate and no burden of legacy, Swift is a new and innovative language with which to develop applications for both iOS and Mac OS X with the advantage that much of the syntax will be familiar to those with experience of other programming languages.

The introduction of Swift aside, it is still perfectly acceptable to continue to develop applications using Objective-C. Indeed, it is also possible to mix both Swift and Objective-C within the same application code base. That being said, Apple clearly sees the future of iOS and Mac OS X development in terms of Swift rather than Objective-C. In recognition of this fact, all of the examples in this book are implemented using Swift. Before moving on to those examples, however, the next several chapters will provide an overview and introduction to Swift programming. The intention of these chapters is to provide enough information so that you can begin to confidently program using Swift. For an exhaustive and in-depth guide to all the features, intricacies and capabilities of Swift, some time spent reading Apple’s excellent book entitled “The Swift Programming Language” (available free of charge from within the Apple iBookStore) is strongly recommended.


Contents


Using a Swift Playground

Both this and the following few chapters are intended to introduce the basics of the Swift programming language. As outlined in the previous chapter, entitled An Introduction to Swift Playgrounds the best way to learn Swift is to experiment within a Swift playground environment. Before starting this chapter, therefore, create a new playground and use it to try out the code in both this and the other Swift introduction chapters that follow.

Swift Data Types

When we look at the different types of software that run on computer systems and mobile devices, from financial applications to graphics intensive games, it is easy to forget that computers are really just binary machines. Binary systems work in terms of 0 and 1, true or false, set and unset. All the data sitting in RAM, stored on disk drives and flowing through circuit boards and buses are nothing more than sequences of 1s and 0s. Each 1 or 0 is referred to as a bit and bits are grouped together in blocks of 8, each group being referred to as a byte. When people talk about 32-bit and 64-bit computer systems they are talking about the number of bits that can be handled simultaneously by the CPU bus. A 64-bit CPU, for example, is able to handle data in 64-bit blocks, resulting in faster performance than a 32-bit based system.

Humans, of course, don't think in binary. We work with decimal numbers, letters and words. In order for a human to easily (easily being a relative term in this context) program a computer, some middle ground between human and computer thinking is needed. This is where programming languages such as Swift come into play. Programming languages allow humans to express instructions to a computer in terms and structures we understand, and then compile that down to a format that can be executed by a CPU.

One of the fundamentals of any program involves data, and programming languages such as Swift define a set of data types that allow us to work with data in a format we understand when programming. For example, if we want to store a number in a Swift program we could do so with syntax similar to the following:

var mynumber = 10

In the above example, we have created a variable named mynumber and then assigned to it the value of 10. When we compile the source code down to the machine code used by the CPU, the number 10 is seen by the computer in binary as:

1010

Similarly, we can express a letter, the visual representation of a digit ('0' through to '9') or punctuation mark (referred to in computer terminology as characters) using the following syntax:

var myletter = "c"

Once again, this is understandable by a human programmer, but gets compiled down to a binary sequence for the CPU to understand. In this case, the letter 'c' is represented by the decimal number 99 using the ASCII table (an internationally recognized standard that assigns numeric values to human readable characters). When converted to binary, it is stored as:

10101100011

Now that we have a basic understanding of the concept of data types and why they are necessary we can take a closer look at some of the more commonly used data types supported by Swift.


Integer Data Types

Swift integer data types are used to store whole numbers (in other words a number with no decimal places). Integers can be signed (capable of storing positive, negative and zero values) or unsigned (positive and zero values only).

Swift provides support for 8, 16, 32 and 64 bit integers (represented by the Int8, Int16, Int32 and Int64 types respectively). The same variants are also available for unsigned integers (UInt8, UInt16, UInt32 and UInt64).

In general, Apple recommends using the Int data type rather than one of the above specifically sized data types. The Int data type will use the appropriate integer size for the platform on which the code is running.

All integer data types contain bounds properties which can be accessed to identify the minimum and maximum supported values of that particular type. The following code, for example, outputs the minimum and maximum bounds for the 32-bit signed integer data type:

print("Int32 Min = \(Int32.min) Int32 Max = \(Int32.max)")

When executed, the above code will generate the following output:

Int32 Min = -2147483648 Int32 Max = 2147483647

Floating Point Data Types

The Swift floating point data types are able to store values containing decimal places. For example, 4353.1223 would be stored in a floating point data type. Swift provides two floating point data types in the form of Float and Double. Which type to use depends on the size of value to be stored and the level of precision required. The Double type can be used to store up to 64-bit floating point numbers with a level of precision of 15 decimal places or greater. The Float data type, on the other hand, is limited to 32-bit floating point numbers and offers a level of precision as low as 6 decimal places depending on the native platform on which the code is running.

Bool Data Type

Swift, like other languages, includes a data type for the purpose of handling true or false (1 or 0) conditions. Two Boolean constant values (true and false) are provided by Swift specifically for working with Boolean data types.

Character Data Type

The Swift Character data type is used to store a single character of rendered text such as a letter, numerical digit, punctuation mark or symbol. Internally characters in Swift are stored in the form of grapheme clusters. A grapheme cluster is made of two or more Unicode code points that are combined to represent a single visible character.

The following lines assign a variety of different characters to Character type variables:

var myChar1 = "f"
var myChar2 = ":"
var myChar3 = "X"

Characters may also be referenced using Unicode code points. The following example assigns the ‘X’ character to a variable using Unicode:

var myChar4 = "\u{0058}"

String Data Type

The String data type is a sequence of characters that typically make up a word or sentence. In addition to providing a storage mechanism, the String data type also includes a range of string manipulation features allowing strings to be searched, matched, concatenated and modified.

Strings can also be constructed using combinations of strings, variables, constants, expressions, and function calls using a concept referred to as string interpolation. For example, the following code creates a new string from a variety of different sources using string interpolation before outputting it to the console:

var userName = "John"
var inboxCount = 25
let maxCount = 100

var message = "\(userName) has \(inboxCount) message. Message capacity remaining is \(maxCount - inboxCount)"

print(message)

When executed, the code will output the following message:

John has 25 messages. Message capacity remaining is 75 messages.

Special Characters/Escape Sequences

In addition to the standard set of characters outlined above, there is also a range of special characters (also referred to as escape sequences) available for specifying items such as a new line, tab or a specific Unicode value within a string. These special characters are identified by prefixing the character with a backslash (a concept referred to as escaping). For example, the following assigns a new line to the variable named newline:

var newline = "\n"

In essence, any character that is preceded by a backslash is considered to be a special character and is treated accordingly. This raises the question as to what to do if you actually want a backslash character. This is achieved by escaping the backslash itself:

var backslash = "\\"

Commonly used special characters supported by Swift are as follows:

  • \n - New line
  • \r - Carriage return
  • \t - Horizontal tab
  • \\ - Backslash
  • \" - Double quote (used when placing a double quote into a string declaration)
  • \' - Single quote (used when placing a single quote into a string declaration)
  • \u{nn} – Single byte Unicode scalar where nn is replaced by two hexadecimal digits representing the Unicode character.
  • \u{nnnn} – Double byte Unicode scalar where nnnn is replaced by four hexadecimal digits representing the Unicode character.
  • \U{nnnnnnnn} – Four byte Unicode scalar where nnnnnnnn is replaced by eight hexadecimal digits representing the Unicode character.

Swift Variables

Variables are essentially locations in computer memory reserved for storing the data used by an application. Each variable is given a name by the programmer and assigned a value. The name assigned to the variable may then be used in the Swift code to access the value assigned to that variable. This access can involve either reading the value of the variable, or changing the value. It is, of course, the ability to change the value of variables which gives them the name variable.

Swift Constants

A constant is similar to a variable in that it provides a named location in memory to store a data value. Constants differ in one significant way in that once a value has been assigned to a constant it cannot subsequently be changed.

Constants are particularly useful if there is a value which is used repeatedly throughout the application code. Rather than use the value each time, it makes the code easier to read if the value is first assigned to a constant which is then referenced in the code. For example, it might not be clear to someone reading your Swift code why you used the value 5 in an expression. If, instead of the value 5, you use a constant named interestRate the purpose of the value becomes much clearer. Constants also have the advantage that if the programmer needs to change a widely used value, it only needs to be changed once in the constant declaration and not each time it is referenced.

As with variables, constants have a type, a name and a value. Unlike variables, however, once a value has been assigned to a constant, that value cannot subsequently be changed.

Declaring Constants and Variables

Variables are declared using the var keyword and may be initialized with a value at creation time. If the variable is declared without an initial value it must be declared as being optional (a topic which will be covered later in this chapter). The following, for example, is a typical variable declaration:

var userCount = 10

Constants are declared using the let keyword.

let maxUserCount = 20

For greater code efficiency and execution performance, Apple recommends the use of constants rather than variables whenever possible.

Type Annotations and Type Inference

Swift is categorized as a type safe programming language. This essentially means that once the data type of a variable has been identified, that variable cannot subsequently be used to store data of any other type without inducing a compilation error. This contrasts to loosely typed programming languages where a variable, once declared, can subsequently be used to store other data types.

There are two ways in which the type of a constant or variable will be identified. One approach is to use a type annotation at the point the variable or constant is declared in the code. This is achieved by placing a colon after the constant or variable name followed by the type declaration. The following line of code, for example, declares a variable named userCount as being of type Int:

var userCount: Int = 10

In the absence of a type annotation in a declaration, the Swift compiler uses a technique referred to as type inference to identify the type of the constant or variable. When relying on type inference, the compiler looks to see what type of value is being assigned to the constant or variable at the point that it is initialized and uses that as the type. Consider, for example, the following variable and constant declarations:

var signalStrength = 2.231
let companyName = "My Company"

During compilation of the above lines of code, Swift will infer that the signalStrength variable is of type Double (type inference in Swift defaults to Double for all floating point numbers) and that the companyName constant is of type String.

When a constant is declared without a type annotation it must be assigned a value at the point of declaration:

let bookTitle = "iOS 9 App Development Essentials"

If a type annotation is used when the constant is declared, however, the value can be assigned later in the code. For example:

let bookTitle: String
.
.
if iosBookType {
	bookTitle = "iOS 9 App Development Essentials"
} else {
	bookTitle = "Android Studio Development Essentials"
}

It is important to note that a value may only be assigned to a constant once. A second attempt to assign a value to a constant will result in a syntax error.

The Swift Tuple

Before proceeding, now is a good time to introduce the Swift tuple. The tuple is perhaps one of the simplest, yet most powerful features of the Swift programming language. A tuple is, quite simply, a way to temporarily group together multiple values into a single entity. The items stored in a tuple can be of any type and there are no restrictions requiring that those values all be of the same type. A tuple could, for example, be constructed to contain an Int value, a Float value and a String as follows:

let myTuple = (10, 432.433, “This is a String”)

The elements of a tuple can be accessed using a number of different techniques. A specific tuple value can be accessed simply by referencing the index position (with the first value being at index position 0). The code below, for example, extracts the string resource (at index position 2 in the tuple) and assigns it to a new string variable:

let myTuple = (10, 432.433, "This is a String")
let myString = myTuple.2
print(myString)

Alternatively, all of the values in a tuple may be extracted and assigned to variables or constants in a single statement:

let (myInt, myFloat, myString) = myTuple

This same technique can be used to extract selected values from a tuple whilst ignoring others by replacing the values to be ignored with an underscore character. The following code fragment extracts the integer and string values from the tuple and assigns them to variables, but ignores the floating point value:

var (myInt, _, myString) = myTuple

When creating a tuple it is also possible to assign a name to each value:

let myTuple = (count: 10, length: 432.433, message: "This is a String")

The names assigned to the values stored in a tuple may then be used to reference those values in code. For example to output the message string value from the myTuple instance, the following line of code could be used:

print(myTuple.message)

Perhaps the most powerful use of tuples is, as will be seen in later chapters, the ability to return multiple values from a function.

Learn SwiftUI and take your iOS Development to the Next Level
SwiftUI Essentials – iOS 16 Edition book is now available in Print ($39.99) and eBook ($29.99) editions. Learn more...

Buy Print Preview Book

The Swift Optional Type

The Swift optional data type is a new concept that does not exist in most other programming languages. The purpose of the optional type is to provide a safe and consistent approach to handling situations where a variable or constant may not have any value assigned to it.

Variables are declared as being optional by placing a ? character after the type declaration. The following code declares an optional Int variable named index:

var index: Int?

The variable index can now either have an integer value assigned to it, or have nothing assigned to it. Behind the scenes, and as far as the compiler and runtime are concerned, an optional with no value assigned to it actually has a value of nil.

An optional can easily be tested (typically using an if statement) to identify whether or not it has a valueriable assigned to it as follows:

var index: Int?

if index != nil {
    // index variable has a value assigned to it
} else {
    // index variable has no value assigned to it
}

If an optional has a value assigned to it, that value is said to be “wrapped” within the optional. The value wrapped in an optional may be accessed using a concept referred to as forced unwrapping. This simply means that the underlying value is extracted from the optional data type, a procedure that is performed by placing an exclamation mark (!) after the optional name.

To explore this concept of unwrapping optional types in more detail, consider the following code:

var index: Int?

index = 3

var treeArray = ["Oak", "Pine", "Yew", "Birch"]

if index != nil {
    print(treeArray[index!])
} else {
    print("index does not contain a value")
}

The code simply uses an optional variable to hold the index into an array of strings representing the names of tree types (Swift arrays will be covered in more detail in the chapter entitled Working with Array and Dictionary Collections in Swift). If the index optional variable has a value assigned to it, the tree name at that location in the array is printed to the console. Since the index is an optional type, the value has been unwrapped by placing an exclamation mark after the variable name:

print(treeArray[index!])

Had the index not been unwrapped (in other words the exclamation mark omitted from the above line), the compiler would have issued an error similar to the following: Value of optional type Int? not unwrapped

As an alternative to forced unwrapping, the value assigned to an optional may be allocated to a temporary variable or constant using optional binding, the syntax for which is as follows:

if let constantname = optionalName {

}

if var variablename = optionalName {

}

The above constructs perform two tasks. In the first instance, the statement ascertains whether or not the designated optional contains a value. Secondly, in the event that the optional has a value, that value is assigned to the declared constant or variable and the code within the body of the statement is executed. The previous forced unwrapping example could, therefore, be modified as follows to use optional binding instead:

var index: Int?

index = 3

var treeArray = ["Oak", "Pine", "Yew", "Birch"]

if let myvalue = index {
    print(treeArray[myvalue])
} else {
    print("index does not contain a value")
}

In this case the value assigned to the index variable is unwrapped and assigned to a temporary constant named myvalue which is then used as the index reference into the array. Note that the myvalue constant is described as temporary since it is only available within the scope of the if statement. Once the if statement completes execution, the constant will no longer exist.

Optional binding may also be used to unwrap multiple optionals and include a Boolean test condition, the syntax for which is as follows:

if let constname1 = optName1, constname2 = optName2, optName3 = … where <boolean statement> {

}

The following code, for example, uses optional binding to unwrap two optionals within a single statement:

var pet1: String?
var pet2: String?

pet1 = "cat"
pet2 = "dog"

if let firstPet = pet1, secondPet = pet2 {
    print(firstPet)
    print(secondPet)
} else {
    print("insufficient pets")
}

The code fragment below, on the other hand, also makes use of the where clause to test a Boolean condition:

if let firstPet = pet1, secondPet = pet2 where petCount > 1 {
    print(firstPet)
    print(secondPet)
} else {
    print("no pets")
}

In the above example, the optional binding will not be attempted unless the value assigned to petCount is greater than 1.

It is also possible to declare an optional as being implicitly unwrapped. When an optional is declared in this way, the underlying value can be accessed without having to perform forced unwrapping or optional binding. An optional is declared as being implicitly unwrapped by replacing the question mark (?) with an exclamation mark (!) in the declaration. For example:

var index: Int! // Optional is now implicitly unwrapped

index = 3

var treeArray = ["Oak", "Pine", "Yew", "Birch"]

if index != nil {
    print(treeArray[index])

} else {
    print("index doex not contain a value")
}

With the index optional variable now declared as being implicitly unwrapped, it is no longer necessary to unwrap the value when it is used as an index into the array in the above print call.

One final observation with regard to optionals in Swift is that only optional types are able to have no value or a value of nil assigned to them. In Swift it is not, therefore, possible to assign a nil value to a non-optional variable or constant. The following declarations, for instance, will all result in errors from the compiler since none of the variables are declared as optional:

var myInt = nil // Invalid code
var myString: String = nil // Invalid Code
let myConstant = nil // Invalid code

Type Casting and Type Checking

When writing Swift code, situations will occur where the compiler is unable to identify the specific type of a value. This is often the case when a value of ambiguous or unexpected type is returned from a method or function call. In this situation it may be necessary to let the compiler know the type of value that your code is expecting or requires using the as keyword (a concept referred to as type casting).

The following code, for example, lets the compiler know that the value returned from the objectForKey method needs to be treated as a String type:

let myValue = record.objectForKey("comment") as! String

In fact, there are two types of casting which are referred to as upcasting and downcasting. Upcasting occurs when an object of a particular class is cast to one of its superclasses. Upcasting is performed using the as keyword and is also referred to as guaranteed conversion since the compiler can tell from the code that the cast will be successful. The UIButton class, for example, is a subclass of the UIControl class as shown in the fragment of the UIKit class hierarchy shown in Figure 6-1:


Swift 2 upcasting diagram

Figure 6-1


Since UIButton is a subclass of UIControl, the object can be safely upcast as follows:

let myButton: UIButton = UIButton()

let myControl = myButton as UIControl 

Downcasting, on the other hand, occurs when a conversion is made from one class to another where there is no guarantee that the cast can be made safely or that an invalid casting attempt will be caught by the compiler. When an invalid cast is made in downcasting and not identified by the compiler it will most likely lead to an error at runtime.

Downcasting usually involves converting from a class to one of its subclasses. Downcasting is performed using the as! keyword syntax and is also referred to as forced conversion. Consider, for example, the UIKit UIScrollView class which has as subclasses both the UITableView and UITextView classes as shown in Figure 6-2:


Swift 2 downcast diagram

Figure 6-2


In order to convert a UIScrollView object to a UITextView class a downcast operation needs to be performed. The following code attempts to downcast a UIScrollView object to UITableView using the guaranteed conversion or upcast approach:

let myScrollView: UIScrollView = UIScrollView()

let myTextView = myScrollView as UITextView

When compiled, the above code will result in the following error:

‘UIScrollView’ is not convertible to ‘UITextView’

The compiler is indicating that a UIScrollView instance cannot be safely converted to a UITextView class instance. This does not mean that it is incorrect to do so, the compiler is simply stating that it cannot guarantee the safety of the conversion for you. The downcast conversion must instead be forced using the as! Annotation:

let myTextView = myScrollView as! UITextView

Another useful approach to downcasting is to perform an optional binding using as?. If the conversion is performed successfully, an optional value of the specified type is returned, otherwise the optional value will be nil:

if let classB = classA as? UITextView {
    print("Type cast to UITextView succeeded")
} else {
    print("Type cast to UITextView failed")
}

It is also possible to type check a value using the is keyword. The following code, for example, checks that a specific object is an instance of a class named MyClass:

if myobject is MyClass {
	// myobject is an instance of MyClass
}

Summary

This chapter has begun the introduction to Swift by exploring data types together with an overview of how to declare constants and variables. The chapter has also introduced concepts such as type safety, type inference and optionals, each of which is an integral part of Swift programming and designed specifically to make code writing less prone to error.


Learn SwiftUI and take your iOS Development to the Next Level
SwiftUI Essentials – iOS 16 Edition book is now available in Print ($39.99) and eBook ($29.99) editions. Learn more...

Buy Print Preview Book



PreviousTable of ContentsNext
An Introduction to Xcode 7 PlaygroundsSwift 2 Operators and Expressions