SWIFT


@ALL NOTES OR PROGRAM ARE COLLECTED FROM SOLOLEARN





Welcome to Swift!



Swift combines the best of C and Objective-C.

It's ideal for creating new apps and works seamlessly with Objective-C, so it's compatible with apps previously created in that language.
Swift is ready for your next iOS and OSX project - or for addition into your current app - because Swift code works side-by-side with Objective-C.
We will be covering Swift version 4 in this course.

"Hello World"



Printing text is easy:
print("Hello, world!")Try It Yourself

To print the value of a variable inside a text, place it in parentheses, and insert a backslash just prior to the opening parenthesis:
print("The value is \(myVariable)")Try It Yourself
You do not need the backslash for printing only the variable value:
print(myVariable)Try It Yourself

Use of the semicolon (;) following each statement is fully optional in Swift, unless you wish to place several independent statements on a single line, in which case the semi-colon is required.

Comments



The Swift compiler ignores comments, which are used to include non-executable text in your code that may be used as a reminder or note-to-self.
A single-line comment opens with two forward-slashes (//):// this is a comment
A multiline comment begins with a single forward-slash, followed by an asterisk (/*). It concludes with an asterisk, then a forward-slash (*/):/* this is also a comment,
but written over multiple lines */

Multiline comments in Swift can be nested within other multiline comments.

Constants and Variables



Constants and variables are used to associate a name (yourName or welcomeMessage) with a value (the number 42 or the string "Hi!").
constant has a set value that cannot be changed; the value of a variable can be changed.

The keyword var is used to declare a variable.
The following example declares a variable, "a", and assigns its value as "42".
var a = 42Try It Yourself

It is possible to change variable values over time:
a = 88
// Now "a" has a value of 88.
Try It Yourself

Multiple variables can be declared on a single line, separated with commas.

Constants



Declare a constant using the let keyword.
This example declares a constant named "one" and assigns it a value of 1:
let one = 1Try It Yourself

Declare multiple constants on a single line and separate them with commas:
let x = 0.0, y = 0.0, z = 0.0Try It Yourself

The value of a constant can never be changed. Trying to assign a new value to a constant results in an error.

Constant and Variable Names



Constant and variable names can contain almost any character, including Unicode characters:
However, constant and variable names must have no blank spaces, mathematical symbols, arrows, private-use (or invalid) Unicode code points, or line and box-drawing characters. Numbers can appear anywhere within a name, except for at the beginning.
Constants or variables of a certain type can't be declared again with the same name, nor can they be altered to store values of differing types. Also, a constant cannot be made a variable, nor can a variable be made a constant.

Type Annotations



Type annotations ensure that your code is clear about the value stored within your constant or variable. Swift's basic types include:
Int: Integers
Double and Float: Floating-Point Values
Bool: Boolean Values
String: Textual Data.

Add a type annotation by placing a colon (:) after the constant or variable name, then add a space, and then add the type name, as follows:
var welcomeMsg: String
welcomeMsg = "Hello"
Try It Yourself

This example provides a type annotation for a variable called "welcomeMsg", that indicates that the variable can store String values.
It's possible to define multiple related variables of the same type. Include them all on a single line, separated by commas, then add a single type annotation after the final variable name:
var red, green, blue: Double



Type Annotations



In practice, you will rarely need to add type annotations. Providing an initial value for a constant or a variable at the point at which it is defined, will almost always be sufficient for Swift to infer which type should be used:
let pi = 3.14159 //DoubleTry It Yourself

Swift always chooses Double (as opposed to Float) when inferring the type for floating-point numbers.
Swift is a type safe language, meaning that it supports clarity when specifying value types for code. When part of your code expects a String, you can't pass it an Int by mistake.

Basic Operators



An operator is a special symbol or phrase used to check, change, or combine values.

Operators are unary, binary, or ternary:
-Unary Operator: Has a single target (-a). A unary prefix operator is placed before the target (!b).
-Binary Operator: Has two targets (4 + 5) and is infixed, appearing between the two targets.
-Ternary Operator: Has three targets. Like C, Swift has one ternary operator, the ternary conditional operator (a ? b : c).
The values targeted by operators are called operands. In the expression 1 + 2, the + symbol is a binary operator; its two operands are the values 1 and 2.

Assignment Operator



The assignment operator (a = b) initializes or updates the value of a with the value of b:
let b = 7
var a = 42
a = b // a is now equal to 7
Try It Yourself

Arithmetic Operators



Swift supports the four standard arithmetic operators for all number types:

Addition (+)
1 + 2 // equals 3Try It Yourself

Subtraction (-)
6 - 2 // equals 4Try It Yourself

Multiplication (*)
4 * 3 // equals 12Try It Yourself

Division (/)
10.0 / 2.5 // equals 4.0Try It Yourself

The addition operator is also supported for String concatenation:
"Hello, " + "world" // equals "Hello, world"Try It Yourself

Tap Try It Yourself to play around with the code!

Remainder Operator



The remainder operator (a % b) calculates the number of multiples of b that fit within a, and returns the value that is left over, or the remainder.
9 % 4 // equals 1Try It Yourself

In other languages, the remainder operator (%) is called a modulo operator. In Swift, however, its behavior for negative numbers means that it is, strictly speaking, a remainder, rather than a modulo operation.

Compound Operators



Like C, Swift provides compound operators that combine assignment (=) with another operation.
var a = 1
a += 2
// a is now equal to 3
Try It Yourself

The expression a += 2 is shorthand for a = a + 2. The addition and the assignment are combined into one operator that performs both tasks at the same time.
Similarly, there are shorthand operators for other arithmetic operations.

Comparison Operators



Swift supports all of the standard comparison operators in C:
Equal to (a == b)
Not equal to (a != b)
Greater than (a > b)
Less than (a < b)
Greater than or equal to (a >= b)
Less than or equal to (a <= b)

Each of the comparison operators returns a Bool value indicating whether or not the statement is true:
1 == 1 // true, because 1 is equal to 1
2 != 1 // true, because 2 is not equal to 1
2 > 1 // true, because 2 is greater than 1
1 < 2 // true, because 1 is less than 2
1 >= 1 // true, because 1 is greater than or equal to 1
2 <= 1 // false, because 2 is not less than or equal to 1
Try It Yourself

Swift also provides two identity operators, === and !==, which test whether two object references both refer to the same object instance.

Ternary Conditional Operator



The ternary conditional operator is a special operator with three parts, taking the form (question ? answer1 : answer2).

This operator acts as a shortcut in evaluating one of two expressions, based on whether the question is true or false. For a true question, it evaluates answer1 and returns its value; otherwise, it evaluates answer2 and returns its value.
gender == 0 ? print("male") : print("female")Try It Yourself

The example above will evaluate the expression gender == 0. If true, it prints "male". Otherwise, it prints "female".

Range Operators



Swift offers two range operators, which are shortcuts for expressing a range of values.

The closed range operator (a...b) defines a range running from a to b, and includes the values a and b. The value of a must not be greater than that of b.
1...3 //1, 2, 3Try It Yourself

The half-open range operator (a..<b) defines a range that runs from a to b, but does not include b. It is said to be half-open because it contains its first value, but not its final value. As with the closed range operator, the value of a must not be greater than that of b.
1..<3 //1, 2Try It Yourself

You will understand the functions of range operators in the upcoming lessons.

Logical Operators



Logical operators modify or combine the Boolean logic values true and false. Swift supports the three standard logical operators found in C-based languages:

Logical NOT operator (!a): Inverts a Boolean value so that true becomes false and false becomes true.

Logical AND operator (a && b): Creates logical expressions in which both values must be true for the overall expression to be true.

Logical OR operator (a || b): An infixed operator made from two adjacent pipe characters. It creates logical expressions in which only one of the two values has to be true for the overall expression to be true.
Multiple logical operators can be combined to create longer compound expressions.
The logical operators && and || are left-associative, meaning that compound expressions with multiple logical operators evaluate the leftmost subexpression before the right.

Optionals



Optionals are used in situations in which a value may be absent.
An optional says:
-There is a value, and it equals x
or
-There isn't a value at all
var myCode: Int? = 404Try It Yourself

An optional Int is written as Int?, not Int. The question mark indicates that the value contained within is optional, meaning that it might contain some Int value, or it might contain no value at all.
It can't contain anything else, such as a Bool value or a String value. It's either an Int, or it's nothing at all.


nil



You set an optional variable to a valueless state by assigning it the special value nil:
var myCode: Int? = 404
myCode = nil
// myCode now contains no value
Try It Yourself

An optional variable with no default value is automatically set to nil for you:
var someMsg: String?
// someMsg is automatically set to nil
Try It Yourself

nil cannot be used with non-optional constants and variables. If your code contains a constant or variable that needs to work with the absence of a value under certain conditions, always declare it as an optional value of the appropriate type.

Conditional Statements



A conditional statement executes certain code under certain conditions. For example, you can run a particular code when an error occurs, or display a message when a value exceeds a certain baseline. To set conditions, use if or switch statements.

The if Statement


The most basic if statement contains a single if condition, and executes a set of statements only if that condition is true:
var temp = 25
if temp <= 30 {
print("It's cold.")
}
Try It Yourself

You can specify additional conditions by chaining together multiple if statements.
if cardValue == 11 {
print("Jack")
} else if cardValue == 12 {
print("Queen")
} else {
print("Not found")
}
Try It Yourself

You can add as many else-if statements as needed.

The switch Statement



Use the switch statement as an alternative to the if statement for multiple potential states. The switch statement compares a value with several possible matching patterns, executing a block of code using the first matching pattern.

Each case begins with the keyword case:
switch distance {
case 0:
print("not a valid distance")
case 1,2,3,4,5:
print("near")
default:
print("too far")
}
Try It Yourself

A single case can contain multiple values, as in our example above. It can also contain ranges, using the range operators.

Every switch statement must be exhaustive, i.e. take every possible value into consideration. In cases in which it is not appropriate to provide a switch case for every possible value, you can define a default catch-all case to cover any values that are not explicitly addressed. Indicate the catch-all case by using the keyword default. This always appears last.
Swift doesn't require break statements, but will still accept one to match and ignore a particular case, or to break out of a matched case before that case has completed its execution.

Where



The where clause checks for additional conditions.
let myPoint = (1, -1)
switch myPoint {
case let (x, y) where x == y:
print("(\(x), \(y)) is on the line x == y")
case let (x, y) where x == -y:
print("(\(x), \(y)) is on the line x == -y")
case let (x, y):
print("(\(x), \(y)) is just some arbitrary point")
}
Try It Yourself

The three switch cases declare placeholder constants x and y, which temporarily take on the two values from myPoint, creating a dynamic filter as part of a where clause. The switch case matches the current value of point only if the where clause's condition evaluates to true for that value.
The final case matches all possible remaining values; a default case is not necessary to have an exhaustive switch statement.

The while Loop



while loop performs a set of statements until a condition becomes false. These kinds of loops are best used when the number of iterations is not known before the first iteration begins.
while evaluates its condition at the start of each pass through the loop.
The while loop is demonstrated in the example below:
while a < b {
print(a)
a+=1
}
Try It Yourself

The code will execute until the a+=1 statement renders a < b as false.

Repeat-While



The repeat-while loop is the alternate while loop. It first makes a single pass through the loop block, then considers the loop's condition, and repeats the loop until the condition shows as false.
repeat {
x -= 1
} while x > 0
Try It Yourself

Swift's repeat-while loop is similar to a do-while loop in other languages.

The for-in Loop



Use the for-in loop to iterate over a sequence, such as ranges of numbers, items in an array, or characters in a string.
The following example prints the first few entries in the five-times-table:
for index in 1...5 {
print("\(index) times 5 is \(index * 5)")
}
// 1 times 5 is 5
// 2 times 5 is 10
// 3 times 5 is 15
// 4 times 5 is 20
// 5 times 5 is 25
Try It Yourself

The index variable is set at the first value in the range (1). The statements within the for loop are then executed in sequence, through the final item in the range (5).

Control Transfer



Control transfer statements alter the code execution by transferring control from one piece of code to another. Swift's four control transfer statements are continuebreakfallthrough, and return (which will be discussed in the upcoming lessons).

Continue


The continue statement stops the loop, then restarts it at the beginning of its next cycle.
The example below shows how to use the continue statement to skip over even numbers.
for num in 1...10 {
if num%2 == 0 {
continue
}
print(num)
}
Try It Yourself

A for loop with a condition and an incrementer still evaluates the incrementer after the continue statement is initiated. The loop itself continues to work as usual; only the code within the loop's body is skipped.

Break



Use the break statement to immediately end the execution of an entire control flow statement. Also, the break statement is used within a switch statement or a loop statement to terminate its execution sooner than would otherwise be the case.

Break in a Loop Statement


When a break statement is used within a loop statement, the loop's execution immediately stops. Control transfers to the first line of code following the loop's closing brace (}). The current iteration's remaining code is skipped, and no further iterations of the loop are initiated.
For example, you can have a loop that breaks out when the value of a becomes less than that of b:
var b = 7
var a = 10
while a > 0 {
if(a < b) {
break
}
a-=1
}
Try It Yourself

Break in a Switch Statement


break causes a switch statement to end its execution immediately, and transfers control to the first line of code that follows the switch statement's closing brace (}).
var a = 5
var letter = "X"
switch a {
case 1:
letter = "A"
case 2:
letter = "B"
default:
break
}
Try It Yourself

This example breaks out of the switch statement as soon as the default case is matched.
Always use a break statement to ignore a switch case.

Fallthrough



In Swift, switch statements do not fall through the bottom of each case into the next. Instead, the entire switch statement completes its execution when the first matching case is completed.
By contrast, C requires insertion of an explicit break statement at the end of every switch case to prevent fallthrough. By eliminating default fallthrough, Swift allows for more concise and predictable switch statements in comparison with C, and thus avoids inadvertently executing multiple switch cases.

In cases that require C-style fallthrough behavior, use the fallthrough keyword on a case-by-case basis. The example below uses fallthrough to create a number's textual description.
let myInt = 5
var desc = "The number \(myInt) is"
switch myInt {
case 2, 3, 5, 7, 11, 13, 17, 19:
desc += " a prime number, and also"
fallthrough
default:
desc += " an integer."
}
print(desc)
Try It Yourself

This prints "The number 5 is a prime number, and also an integer."

If myInt's value is one of the prime numbers in the list, text noting that the number is prime is appended to the end of the description. The fallthrough keyword then causes it to "fall into" the default case.
The fallthrough keyword does not check case conditions in the switch case into which execution falls. As with C’s standard switch statement behavior, the fallthrough keyword moves code execution directly to the statements inside the next (or default) case block.

Strings



string is an ordered collection of characters, such as "Hello, World" or "SoloLearn". Swift strings are represented by the String type, which in turn represents a collection of Character type values.

Predefined String values can be included within code as string literals, or fixed sequences of textual characters within double quotation marks (""). Use a string literal as an initial value for a constant or variable.
let someString = "Some string literal value"Try It Yourself

Because it is initialized with a string literal value, Swift infers a type of String for the someString constant.

Empty Strings



An empty String value can be created as the starting point for a longer string. To do this, either assign an empty string literal to a variable or initialize a new String instance using initializer syntax:
var emptyString = "" // empty string literal
var anotherEmptyString = String() // initializer syntax
Try It Yourself

Both strings are empty and equivalent to each other.
Determine whether a String value is empty by checking its Boolean isEmpty property:
if emptyString.isEmpty {
print("String is empty")
}
Try It Yourself

Tap Try It Yourself to play around with the code!

Concatenation



String values can be added together (or concatenated) with the addition operator (+) to create a new String value:
let string1 = "Hello"
let string2 = " World"
var welcome = string1 + string2
// welcome now equals "Hello World"
Try It Yourself

The addition assignment operator (+=) appends a String value to an existing String variable.
var msg = "Hi"
msg += " David"
// msg is now "Hi David"
Try It Yourself

Tap Try It Yourself to play around with the code!

String Interpolation



String interpolation includes the values of a mix of constants, variables, literals, and expressions inside a string literal to form a new String value. Prefix each item with a backslash, place the item in parentheses, and insert it into the string literal.
let mult = 4
let message = "\(mult) times 1.5 is \(Double(mult) * 1.5)"
// message is "4 times 1.5 is 6"
Try It Yourself

In the above example, the multiplier value is inserted into the string literal as \(mult). When the string interpolation is evaluated prior to creating the actual string, this placeholder is replaced with the actual value of mult.

Later in the string, the value of mult appears within a larger expression within the string literal: \(Double(mult) * 1.5). The expression calculates the value of Double(mult) * 1.5 and then inserts the result (6) into the string.
The expressions appearing inside of parentheses within an interpolated string cannot contain an unescaped double quote ("), backslash (\), carriage return, or line feed.

Counting Characters



To retrieve a count of the Character values in a string, use the count property of the string:
let someString = "I am learning with SoloLearn"
print("someString has \(someString.count) characters")
// prints "someString has 28 characters"
Try It Yourself

When using the characters property, the character count does not always match the length property of an NSString containing the same characters. The length of an NSString is based on the number of 16-bit code units within the string's UTF-16 representation, as opposed to the number of Unicode extended grapheme clusters within the string.

Comparing Strings



Swift offers three options for comparing textual values: string and character equality, prefix equality, and suffix equality.
Use the "equal to" operator (==) and the "not equal to" operator (!=) to determine string and character equality.
let s1 = "We are alike"
let s2 = "We are alike"
if s1 == s2 {
print("These two strings are equal")
}
// prints "These two strings are equal"
Try It Yourself
Use the string's hasPrefix and hasSuffix methods to determine whether a string has a particular string prefix or suffix. Both methods take a single argument of type String and return a Boolean value.


Arrays



An array is an ordered list of values of the same type, in which the same value can appear multiple times at different positions. In Swift, the array type can be written in full as Array<T>, in which T represents which value type the array is allowed to store. The array type can also be expressed in shorthand form, as [T].
Although the two forms are identical in function, the shorthand will appear throughout this tutorial in reference to an array type.

Creating an Empty Array



Create an empty array of a certain type using initializer syntax.
var someInts = [Int]()Try It Yourself

Note that the type of the someInts variable is inferred to be [Int],
from the type of the initializer.

Array with a Default Value



Swift's Array type also provides an initializer for creating an array of a certain size with all of its values set to the same default value. You pass this initializer the number of items to be added to the new array (called count) and a default value of the appropriate type (called repeating):
var fourDoubles = [Double](repeating: 0.0, count: 4)Try It Yourself

fourDoubles is of type [Double], and equals [0.0, 0.0, 0.0, 0.0].

Array Literal



Using an array literal is another way to initialize an array. The array literal is shorthand for one or more values written as an array collection, and is written as a list of values, separated by commas, with square brackets at beginning and end.[value 1, value 2, value 3]
The example below creates an array called shoppingList, for storing String values:
var shoppingList: [String] = ["Bread", "Milk"]Try It Yourself

This particular array can store only String values, as it has String specified as its value type.

Because of Swift's type inference, you don't have to write out the array type. Be sure to initialize with an array literal containing values of that same type. The initialization of shoppingList could have been written in a shorter form:
var shoppingList = ["Bread", "Milk"]Try It Yourself

All values in the array literal are of the same type, enabling Swift to infer that [String] is the correct type for the shoppingList variable.
Combining two existing arrays with compatible types using the addition operator (+) allows you to create a new array. Swift infers the new array's type based on the type of the two combined arrays.

Accessing and Modifying an Array



Access and modify an array through its methods and properties or by using subscript syntax.

An array's read-only count property provides the number of items in an array.
print("The shopping list contains \(shoppingList.count) items.")
// prints "The shopping list contains 2 items."
Try It Yourself

Use the Boolean isEmpty property as a shortcut when you want to know whether the count property is equal to 0.
if shoppingList.isEmpty {
print("The shopping list is empty.")
} else {
print("The shopping list is not empty.")
}
// prints "The shopping list is not empty."
Try It Yourself

Tap Try It Yourself to play around with the code!

Modifying an Array



An array's append method allows you to add a new item at the array's end.
shoppingList.append("Flour")Try It Yourself

Alternatively, add an array of one or more compatible items using the addition assignment operator (+=):
shoppingList += ["Juice"]
shoppingList += ["Chocolate", "Cheese"]
Try It Yourself

Accessing an Array



Using subscript syntax, you can retrieve a value from the array, inserting the index of the value you want to retrieve within square brackets immediately after the name of the array:
var firstItem = shoppingList[0]Try It Yourself

Arrays in Swift are always zero-indexed, meaning that the first item's index is 0, rather than 1, as you might expect.
Accessing or modifying a value for an index that is outside of an array's existing bounds triggers a runtime error. Check the validity of an index prior to using it by comparing it with the array's count property.

Modifying an Array



Use subscript syntax to change an existing value at a given index:
shoppingList[0] = "Two apples"Try It Yourself

Subscript syntax also changes a range of values all at once. This will even work with a replacement set of values with a length that is different from the original range.
In the following example, the elements with index 1, 2, 3 are replaced with two new values.
shoppingList[1...3] = ["Bananas", "Oranges"]Try It Yourself

Don't use subscript syntax to append a new item to an array.

Modifying an Array



An array's insert method will insert an item into the array at a specified index.
shoppingList.insert("Syrup", at: 0)Try It Yourself
"Syrup" is now the first item in the list.

Similarly, the remove method allows you to remove an item from the array. This method removes the item at the specified index, and also returns the removed item. Note that the returned value can be ignored if it is not needed.
let syrup = shoppingList.remove(at:0)Try It Yourself

When an item is removed from an array, Swift closes any gaps that have been created.
If you want to remove the final item from an array, use the removeLast() method rather than the removeAtIndex method to avoid the need to query the array's count property:
let apples = shoppingList.removeLast()
// the last item has just been removed
Try It Yourself

Tap Try It Yourself to play around with the code!

Iterating Over an Array



The for-in loop allows you to iterate over the entire set of values in an array.
for item in shoppingList {
print(item)
}
Try It Yourself

Alternatively, use the enumerated() method to iterate over an array when you need the integer index for each item in addition to its value. This returns a tuple for each item in the array that indicates that item's index and value. You can decompose the tuple into temporary constants or variables as part of the iteration:
for (index, value) in shoppingList.enumerated() {
print("Item \(index + 1): \(value)")
}
Try It Yourself

This will print the index and the value of the elements in the array.
Tuples will be discussed in the upcoming lessons.

Sets



set stores distinct values of the same type in a collection with no defined ordering. Sets are used as an alternative to arrays when item order is not a concern or when you need to ensure that an item appears only once.
For a Swift set, write the type as Set<T> where T is the type that the set is allowed to store. Unlike arrays, there is no equivalent shorthand for sets.
You can create an empty set of a certain type using initializer syntax:
var letters = Set<Character>()Try It Yourself

Based on the initializer type, Swift infers the type of the letters to be Set<Character>.
An array literal will also work as shorthand when initializing a set with one or more values as a set collection.
var names: Set<String> = ["David", "Susan", "Robert"]Try It Yourself

When initializing the type of set with an array literal that contains values of the same type, it is not necessary to write the type of set. The initialization could have been written in a shorter form:
var names: Set = ["David", "Susan", "Robert"]Try It Yourself

Because all values in the array literal are of the same type, Swift infers that Set<String> is the correct type to use for the names variable.

Accessing and Modifying a Set



The count and isEmpty properties work the same way with a set as they do with an array.
Calling the set's insert method adds a new item to a set.
names.insert("Paul")Try It Yourself

You can remove an item from a set by calling the set's remove method. The item is removed if it's a member of the set, and the removed value is returned. It returns nil if the item is not contained in the set. Alternatively, use the set's removeAll() method to remove all of the items in a set.

The contains method tells you whether or not a particular item is present in the set.
if names.contains("James") {
print("James is here.")
} else {
print("James is not with us.")
}
Try It Yourself

Tap Try It Yourself to play around with the code!

Iterating Over a Set



You can iterate over the values in a set with a for-in loop.
for name in names {
print("\(name)")
}
Try It Yourself

Since Swift's Set type does not provide defined ordering, use the sorted() method to iterate over the values of a set in a specific order.
for name in names.sorted() {
print("\(name)")
}
Try It Yourself

Tap Try It Yourself to play around with the code!

Set Operations



Swift allows you to efficiently perform fundamental set operations, such as combining sets, determining which values two sets have in common, or determining whether two sets contain all, some, or none of the same values.

Fundamental Set Operations



The illustration below depicts sets a and b, and shows the results of various set operations, as represented by the shaded regions:
The intersection method creates a new set, with only the values common to both sets.
The symmetricDifference method creates a new set with values in either set, but not both.
The union method creates a new set with all of the values in both sets.
The subtracting method creates a new set with values not in the specified set.

For example, to combine the two sets:
let oddDigits: Set = [1, 3, 5, 7, 9]
let evenDigits: Set = [0, 2, 4, 6, 8]

oddDigits.union(evenDigits).sorted()
// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Try It Yourself

Tap Try It Yourself to play around with the code!

Set Membership and Equality



The illustration below depicts three sets: a, b, and c. The overlapping regions represent the elements that are shared among sets.
Set a is a superset of set b, because a contains all elements in b.
Conversely, set b is a subset of set a, because all elements in b are also contained by a.
Sets b and c are disjointed with one another, because they share no elements in common.
"is equal" operator (==): Determines whether two sets contain all of the same values.
isSubset(of: ) method: Determines whether all of the values of a set are contained in the specified set.
isSuperset(of: ) method: Determines whether a set contains all of the values in a specified set.
isStrictSubset(of: ) or sStrictSuperset(of: ) method: Determines whether a set is a subset or superset of, but not equal to, a specified set.
isDisjoint(with: ) method: determines whether two sets have any values in common.
Spend a little time playing with the methods to learn and understand their functions.

Dictionaries



dictionary stores associations between keys of the same type and values of the same type, in a collection with no defined ordering. Each value is associated with a unique key, which acts as an identifier for that value within the dictionary. A dictionary is used to look up values based on their identifiers, in much the same way that a real-world dictionary is used to look up the definition of a particular word.

Written in its entirety, a Swift dictionary's type is Dictionary<Key, Value>. Key indicates which type of value can be used as a dictionary key, and Value indicates which type of value the dictionary stores for those keys. The shorthand form for the type of a dictionary is [Key: Value].

As with arrays, initializer syntax is used to create an empty Dictionary of a specified type:var airports = [Int: String]()
In the dictionary airports, the keys are of type Int, and the values are of type String.

The Dictionary Literal



A dictionary literal provides a way to write in shorthand one or more key-value pairs as a Dictionary collection.
The key and value in each key-value pair are separated by a colon. The key-value pairs are written as a list, separated by commas, surrounded by a pair of square brackets.
The example below creates a dictionary in which the keys are three-letter codes, and the values are airport names:
var airports: [String: String] = ["TOR": "Toronto", "NY": "New York"]Try It Yourself

As with arrays, it isn't necessary to write the type of the dictionary when initializing it with a dictionary literal whose keys and values have consistent types. The initialization of airports could have been written in a shorter form instead.
var airports = ["TOR": "Toronto", "NY": "New York"]Try It Yourself

Because all keys and values in the literal share the same type, Swift can infer that [String: String] is the correct type to use for the airports dictionary.

Accessing and Modifying a Dictionary



The count and isEmpty properties also work for the dictionary.
Add a new item to a dictionary using subscript syntax:
airports["LHR"] = "London"Try It Yourself

Subscript syntax can be used to change the value associated with a particular key:
airports["LHR"] = "London Heathrow"
// the value for "LHR" has been changed
Try It Yourself

Use a dictionary's updateValue method as an alternative to subscripting when setting or updating a key's value. The updateValue method returns the old value after performing an update:
let oldValue = airports.updateValue("New York", forKey: "NY")Try It Yourself

Subscript syntax is also used to retrieve a value for a particular key from the dictionary.
let airportName = airports["NY"]Try It Yourself

If the value for the requested key does not exist, Swift returns a value of nil.
Use subscript syntax to assign a value of nil to a key in order to remove a key-value pair from a dictionary.
airports["APL"] = "Apple"
airports["APL"] = nil
Try It Yourself

Alternatively, the removeValue(forKey: ) method removes a key-value pair from a dictionary, if the pair exists, and returns the removed value. nil is returned if no value exists.
if let removedValue = airports.removeValue(forKey: "NY") {
print("The removed airport's name is \(removedValue).")
} else {
print("The airports dictionary does not contain a value for NY.")
}
Try It Yourself

Tap Try It Yourself to play around with the code!

Iterating Over a Dictionary



Use a for-in loop to iterate over the key-value pairs in a dictionary. Each item in the dictionary is returned as a (key, value) tuple, which you can decompose into temporary constants or variables as part of the iteration:
for (airportCode, airportName) in airports {
print("\(airportCode): \(airportName)")
}
Try It Yourself

In addition, accessing a dictionary's keys and values properties will retrieve an iterable collection of the dictionary's keys or values.
for airportCode in airports.keys {
print("Airport code: \(airportCode)")
}

for airportName in airports.values {
print("Airport name: \(airportName)")
}
Try It Yourself

Since Swift's Dictionary type does not have a defined ordering, use the sort() method on the dictionary's keys or values property to iterate over the keys or values in a specific order.

Functions



Functions are self-contained chunks of code that perform a specific task. Name a function in a way that identifies what it does, and then use the name to call the function to perform its task when needed.

In Swift, every function has a type that contains the function's parameter types and return type. This type can be used like any other type in Swift, and this makes passing functions as parameters to other functions and returning functions from functions easier.
Functions can also be written within other functions to encapsulate useful functionality within a nested function scope.

Defining and Calling Functions



When you define a function, you have the option of defining one or more named and typed values that the function takes as input (parameters), and/or a type of value that the function passes back as output (return type).

To use a function, call it using its name and pass to it input values (arguments) that match the types of the function's parameters. Arguments must always be provided in the same order as in the function's parameter list. Also, the argument label is mandatory.

The example below defines a function sayHello, which takes a String (personName) as a parameter and then returns another String:
func sayHello(personName: String) -> String {
let greeting = "Hello, " + personName + "!"
return greeting
}
Try It Yourself

The function definition begins with the func keyword. The keyword is followed with a return arrow -> that indicates the function's return type, and the name of the type to return ends the definition.
The return statement indicates the value to be returned by the function.
Once the function has been defined, it can be called in other parts of your code.
print(sayHello(personName: "David"))Try It Yourself

You can call the defined function multiple times, and with different input values.

Multiple Input Parameters



Multiple input parameters can be written within the function's parentheses. Use commas to separate the parameters.
This function takes a start and an end index for a half-open range, and works out how many elements are contained in the range.
func rangeLength(start: Int, end: Int) -> Int {
return end - start
}
print(rangeLength(start: 2, end: 7))
// prints "5"
Try It Yourself

When calling a function parameters, all arguments should be labeled according to its corresponding parameter name.
If you don't want an argument label for a parameter, write an underscore (_) instead of an explicit argument label for that parameter.

Functions Without Parameters



Defining input parameters within a function is not a requirement. It is possible to have a function with no input parameters. That function will return the same String message every time it's called:
func sayHelloWorld() -> String {
return "Hello, world"
}
Try It Yourself

The function definition still needs parentheses after the function's name, even though there may be no parameters. The parentheses following the function name are simply empty when the function is called.

Functions Without Return Values



When defining a function it's not mandatory to define a return type. In the example below, the function sayHi() prints its own String value, rather than returning it.
func sayHi(name: String) {
print("Hi, \(name)!")
}
sayHi(name: "Dave")
// prints "Hi, Dave!"
Try It Yourself

Because it does not need to return a value, the function's definition does not include the return arrow (->) or a return type.
The sayHi() function does still return a value, even though it has no defined return value. Functions without a defined return type return a special value of type Void.
Return values can be ignored, but a function that says it will return a value must always do so.

Multiple Return Values



You can use a tuple type as the return type for a function to return multiple values as part of one compound return value.

The example below defines a function that returns the smallest and largest numbers in an array of Int values:
func minMax(array: [Int]) -> (min: Int, max: Int) {
var currMin = array[0]
var currMax = array[0]
for value in array[1..<array.count] {
if value < currMin {
currMin = value
} else if value > currMax {
currMax = value
}
}
return (currMin, currMax)
}
Try It Yourself

The minMax function returns a tuple containing two Int values. The values are labeled min and max, to facilitate easy access when querying the function's return value.

Because the tuple's member values are named as part of the function's return type, they can be accessed using dot syntax to retrieve the minimum and maximum found values:
let bounds = minMax(array: [4, -4, 1, 88, 7, 42])
print("min is \(bounds.min) and max is \(bounds.max)")
// prints "min is -4 and max is 88"
Try It Yourself

It's not necessary to name the tuple's members when the tuple is returned from the function, because their names have already been specified as part of the function's return type.

External Parameter Names



Function parameters have both an external parameter name and a local parameter name.
The external parameter name is used to label arguments that are passed to a function call, while a local parameter name is used as the function is implemented.
By default, the first parameter omits its external name, and the second and subsequent parameters use their local name as their external name. Each parameter must be given its own, unique local name. External parameters may be shared.

An external parameter name appears just before the local parameter name that it supports. The two parameter names are separated by a space:func someFunc(externalName localName: Int) {
// function can use localName
}

Here's a version of the sayHello() function that takes the names of two people and returns a greeting for both of them:
func sayHello(to p1: String, and p2: String) -> String {
return "Hello \(p1) and \(p2)!"
}
print(sayHello(to: "Tom", and: "Jerry"))
// prints "Hello Tom and Jerry!"
Try It Yourself

The words to and and are the external parameter names, which are used when the function is called. The use of external parameter names can allow a function to be called in an expressive, sentence-like manner, and still produce a readable and clear function body.
If you provide an external parameter name for a given parameter, that external name must be used every time the function is called.

Default Parameter Values



Adding a value after a function parameter's type defines a default value for the parameter. If a default value is defined, that parameter can be omitted when calling the function.
func someFunction(p1: Int = 12) {
// the default value of p1 is 12
}
someFunction(p1: 6) // p1 is 6
someFunction() // p1 is 12
Try It Yourself

Place parameters with default values at the end of a function's parameter list.

Variadic Parameters



Variadic parameters indicate that the number of input values of a specified type passed to the parameter can vary. The variadic parameter can accept zero and/or more parameters of a certain type, and is indicated by adding three period characters (...) immediately following the parameter's type name.

The values passed to a variadic parameter appear as an array of the specified type in the function's body.

In the example below, the function calculates the arithmetic mean, or average, for a list of numbers of any length:
func arithmeticMean(numbers: Double...) -> Double {
var total: Double = 0
for number in numbers {
total += number
}
return (total / Double(numbers.count))
}
Try It Yourself

One variadic parameter is allowed per function. The variadic parameter must always be the last parameter in the list, to ensure clarity when calling the function with multiple parameters.
For a function with one or more parameters containing default values, as well as a variadic parameter, the variadic parameter is added at the very end of the list, following all defaulted parameters.

In-Out Parameters



Function parameters are constants by default. Trying to change the value of a function parameter from within the body of that function results in a compile-time error. This means that you can't change the value of a parameter by mistake. If you want a function to modify a parameter's value, and you want those changes to persist after the function call has ended, define that parameter as an in-out parameter instead.

The inout keyword is placed at the beginning of the parameter's type. Its value is passed in to the function, where it is modified. It's then passed back out of the function, where it replaces the original value.

This example swaps out two Integer values.
func swapInts(a: inout Int, b: inout Int) {
let tempA = a
a = b
b = tempA
}
Try It Yourself

An in-out parameter cannot be assigned a default value. A variadic parameter cannot be marked as inout.
An ampersand (&) that is inserted directly before a variable's name when it's passed as an argument to an inout parameter, indicates that the variable can be modified by the function:
var someInt = 3
var anotherInt = 107
swapInts(a: &someInt, b: &anotherInt)
Try It Yourself

The in-out parameter presents an alternative method when a function is desired to have an effect outside of the scope of its function body.

Function Types



Every function has a specific function type that consists of the function's parameter types and return type. Here's an example:
func addInts(a: Int, b: Int) -> Int {
return a + b
}
func multiplyInts(a: Int, b: Int) -> Int {
return a * b
}
Try It Yourself

This example defines two simple mathematical functions called addInts and multiplyInts, which take two Int values, which return an Int value.
For both of these functions, the type is (Int, Int) -> Int. This can be interpreted as
"A function type that has two parameters, both of type Int; and that returns a value of type Int."

Here's another example. This one shows a function with no parameters or return value:
func printHelloWorld() {
print("Hello, world")
}
Try It Yourself

The type of this function is () -> Void, which translates into "a function that has no parameters, and returns Void."
Tap Continue to learn how you can use function types!

Using Function Types



Function types are used in the same way as any other Swift types.
For example, define a constant or a variable to be of a function type. Then assign an appropriate function to that variable:
var mathFunction: (Int, Int) -> Int = addIntsTry It Yourself

You can now call the assigned function using its name, mathFunction.
print("Result: \(mathFunction(2, 3))")Try It Yourself

A different function with the same type can be assigned to the same variable, in the same way as for non-function types.

Function Types as Parameter Types



A function type, such as (Int, Int) -> Int, can act as a parameter type for a different function, allowing for leaving some aspects of a function's implementation for the function's caller to provide calling the function.
The following example defines a function called printResult, which takes another function as its parameter and calls it as it's implemented:
func printResult(mathFunc: (Int, Int) -> Int, a: Int, b: Int) {
print("Result: \(mathFunc(a, b))")
}
printResult(addInts, a: 3, b: 5)
Try It Yourself

It doesn't matter what the called function's implementation actually does - it matters only that the function is of the correct type.

Function Types as Return Types



A function type may be used as another function's return type, by writing a complete function type immediately following the return arrow (->) in the returning function.
func plus(input: Int) -> Int {
return input + 1
}
func minus(input: Int) -> Int {
return input - 1
}
func chooseFunc(flag: Bool) -> (Int) -> Int {
if(flag) {
return plus
}
else {
return minus
}
}
Try It Yourself

In the above example, the chooseFunc function returns another function of type (Int) -> Int, based on the value of its flag parameter.

Nested Functions



You also have the option of defining functions inside the bodies of other functions. These are called nested functions.

By default, a nested function is hidden from the outside world. It can still be called and used by its enclosing function. An enclosing function can also return one of its nested functions, thus allowing the nested function to be used in another scope.

From the previous lesson, the function chooseFunc can be rewritten to use and return nested functions:
func chooseFunc(flag: Bool) -> (Int) -> Int {
func plus(input: Int) -> Int { return input + 1 }
func minus(input: Int) -> Int { return input - 1 }

if(flag) {
return plus
}
else {
return minus
}
}
Try It Yourself

Tap Try It Yourself to play around with the code!

Recursion



The term recursion is used to describe the situation in which a function calls itself:
func factorial(n: Int) -> Int {
return n == 0 ? 1 : n * factorial(n: n-1)
}
print(factorial(n: 5)) //prints 120
Try It Yourself

The function calls itself recursively, until n is equal to 0, at which point the recursion ends.
Be sure to always add a condition that ends the recursion. Otherwise, your recursion will continue infinitely.

Closures



Closure is a self-contained block of functionality that can be passed around and used in your code.

Global and nested functions are actually special kinds of closures.

Nested functions offer a convenient way to name and define self-contained blocks of code within a larger function.
However, it is sometimes useful to have the option of writing shorter versions of function-like constructs that do not require full declarations and names. This is particularly true when working with functions that take other functions as one or more of their arguments.

Closures



Closure expressions
 present a way to write inline closures using brief, focused syntax. Closure expressions offer a number of syntax optimizations for use in writing closures in a shortened form, without losing clarity or intent.

Closure expression syntax takes the following general form:{ (parameters) -> return type in
statements
}

Closure expression syntax can use constant parameters, variable parameters, and inout parameters, but default values cannot be used. Variadic parameters can be used if you name them and make sure that it's placed last in the parameter list.

The Sorted Function



To understand how Closures are used, let's take a look at a function called sorted, which is available in Swift's standard library. The sorted function orders an array of values of a known type.

The sorted method takes two arguments:
- An array of values of a known type.
- A closure that takes two arguments of the same type as the array's contents, and returns a Bool value to say whether the first value should appear before or after the second value once the sorting is complete.

The example below shows the sorting of an array of String values. The sorting closure needs to be a function of type (String, String) -> Bool.
One way to provide the sorting closure is to write a normal function of the correct type, and to pass it in as the sorted method's parameter:
func backwards(s1: String, s2: String) -> Bool {
return s1 > s2
}
let names = ["Cc", "Aa", "Ee", "Bb", "Dd"]
var reversed = names.sorted(by: backwards)
Try It Yourself

The example compares the Strings in the array names, based on the backwards function.
However, this is a long-winded way to write what is really a function that contains a single-expression (a > b).
In this situation, it would be preferable to write the sorting closure inline, using closure expression syntax:
let names = ["Cc", "Aa", "Ee", "Bb", "Dd"]
var reversed = names.sorted(by: { (s1: String, s2: String) -> Bool in
return s1 > s2
}
)
Try It Yourself

For the inline closure expression, the parameters and return type are written within the curly braces, rather than outside of them.
The in keyword is used to introduce the beginning of the closure's body, and indicates that the definition of the closure's parameters and return type has finished, and the body of the closure is about to begin.

Inferring Type from Context



The sorting closure is passed as an argument to a function, making it possible for Swift to infer the types of its parameters and the type of the return value from the type of the sorted method's second parameter. This parameter expects a function of type (String, String) -> Bool. This means that writing the (String, String) and Bool types as part of the closure expression's definition is not necessary. Because all of the types can be inferred, the return arrow (->) and the parentheses around the names of the parameters can also be omitted:
reversed = names.sorted(by: { s1, s2 in return s1 > s2 } )Try It Yourself

The parameter types and return type can always be inferred when passing a closure to a function as an inline closure expression. As a result, it is unnecessary to write an inline closure in its fullest form when the closure is used as a function argument.
You still have the option of writing out the types. In fact, doing so is encouraged when you need to avoid ambiguity for others who might read your code.

Inferring Type from Context



Single-expression closures can implicitly return the result of their single expression, simply by omitting the return keyword from the declaration, as in this new version of the previous example:
reversed = names.sorted(by: { s1, s2 in s1 > s2 } )Try It Yourself

Here, the function type of the sorted method's second argument makes it clear that a Bool value must be returned by the closure.
Because the closure's body contains a single expression (s1 > s2) that returns a Bool value, there is no ambiguity, and the return keyword can be omitted.

Shorthand Argument Names



Swift automatically provides shorthand argument names for inline closures. These argument names can be used to refer to the values of the closure's arguments, with the names $0$1$2, and so on.

If you use these shorthand argument names within your closure expression, you can omit the closure's argument list from its definition, and the number and type of the shorthand argument names will be inferred from the expected function type. The in keyword can also be omitted, since the closure expression is entirely made up of its body:
reversed = names.sorted(by: { $0 > $1 } )Try It Yourself

Here, $0 and $1 refer to the closure's first and second String arguments.

Operator Functions



There's actually an even shorter way to write the closure expression above. Swift's String type defines its string-specific implementation of the greater-than operator (>) as a function that has two parameters of type String, and returns a value of type Bool. This exactly matches the function type needed for the sort method's second parameter. Just pass in the greater-than operator, and Swift will then infer that you want to use its string-specific implementation:
reversed = names.sorted(by: >)Try It Yourself

Tap Try It Yourself to play around with the code!

Tuples



Tuples group multiple values into a single, compound value. The values within a tuple can be of any type and do not have to share a common type.
let error = (404, "Not Found")Try It Yourself
The tuple above is of type (Int, String).

You can create tuples from any permutation of types, and they can contain as many different types as you like. There's nothing stopping you from having a tuple of type (Int, Int, Int), or (String, Bool), or any other permutation you require.

A tuple's contents can be broken down into separate constants or variables, which you then access as you would any constant or variable.
let (statusCode, statusMessage) = error
print("The status code is \(statusCode)")
// prints "The status code is 404"
print("The status message is \(statusMessage)")
// prints "The status message is Not Found"
Try It Yourself

An alternative method of accessing individual element values in a tuple is to use index numbers, starting with zero.
print("The status code is \(error.0)")
print("The status message is \(error.1)")
Try It Yourself

When you define a tuple, you have the opportunity to name its individual elements. You can then use the element names to access the values of those elements:
let http200Status = (statusCode: 200, description: "OK")
print("The status code is \(http200Status.statusCode)")
print("The status message is \(http200Status.description)")
Try It Yourself

Tuples are particularly useful as the return values of functions, and are used as temporary groupings of related values.

Enumerations



An enumeration defines a common type for a group of related values. It enables you to work with those values in a type-safe way within your code.
Use the enum keyword to introduce an enumeration, and place their entire definition within a pair of braces:enum Compass {
case North
case South
case East
case West
}

An enumeration's member values, or members, are the values that are defined within the enumeration, such as North, South, East, and West. The case keyword indicates that a new line of member values is about to be defined.
Unlike C and Objective-C, Swift enumeration members are not assigned a default integer value when they are created.
In the Compass example above, North, South, East and West do not implicitly equal 0, 1, 2 and 3. Instead, the different enumeration members are fully-fledged values in their own right, with an explicitly defined type of Compass.

Enumerations



Multiple member values can appear on a single line, separated by commas:enum Planet {
case Mercury, Venus, Earth, Mars, Jupiter
}

Each enumeration definition specifies a brand new type. As with other types in Swift, their names (such as Compass and Planet) should be capitalized.

The values in an enumeration can be accessed using the dot syntax.
var direction = Compass.WestTry It Yourself

Give enumeration types singular rather than plural names, so that they read as self-evident.

Classes and Structures



Classes and structures are general-purpose, flexible constructs that become the building blocks of your program's code. You define properties and methods to add functionality to your classes and structures by using exactly the same syntax as for constants, variables, and functions.

Swift does not require that you create separate interface and implementation files for custom classes and structures. Rather, they are defined in a single file. The external interface to that class or structure is automatically made available for other code to use.
In other languages, an instance of a class is traditionally known as an object. However, because classes and structures in Swift are much closer in functionality than in other languages, the more general term instance is used.

Definition



Classes and structures have a similar definition syntax.
You introduce classes with the class keyword and structures with the struct keyword. Each places its entire definition within a pair of braces.
struct Resolution {
var width = 0
var height = 0
}

class VideoMode {
var resolution = Resolution()
var interlaced = false
var frameRate = 0.0
}
Try It Yourself

The example above defines a new structure called Resolution, with two stored properties called width and height.
It also defines a new class called VideoMode, which has three variable stored properties. The first, resolution, is initialized with a new Resolution structure instance, which infers a property type of Resolution.
When a new class or structure is defined, a brand new Swift type is defined.

Class and Structure Instances



The Resolution structure definition and the VideoMode class definition only describe what each one will look like. The definitions in themselves do not describe a specific resolution or video mode. To do that, you need to create an instance of the structure or class.

The syntax for creating instances is very similar for both structures and classes:
let someResolution = Resolution()
let someVideoMode = VideoMode()
Try It Yourself

When creating new instances, structures and classes both use initializer syntax. The simplest form of initializer syntax uses the type name of the class or structure, followed by empty parentheses.
This creates a new instance of the class or structure. Properties are initialized to their default values.

Accessing Properties



Access an instance's properties with dot syntax. Write the property name immediately after the instance name, separated with a period (.), with no spaces:
print("The width is \(someResolution.width)")Try It Yourself

In this example, someResolution.width refers to the width property of someResolution, and returns its value.

You can drill down into a sub-property, such as the width property, which is in the resolution property of a VideoMode.
print(someVideoMode.resolution.width)Try It Yourself

Dot syntax is also used when assigning a new value to a variable property.
someVideoMode.resolution.width = 1280Try It Yourself

In the last example, the width property of the resolution property of someVideoMode is set directly, with no need to set the entire resolution property to a new value.
All structures have an automatically-generated memberwise initializer, which you can use to initialize the member properties of new structure instances. Initial values for the properties of the new instance can be passed to the memberwise initializer by name:
let vga = Resolution(width: 640, height: 480)Try It Yourself

Unlike structures, class instances do not receive a memberwise initializer by default.

Structures are Value Types



value type is a type whose value is copied when it is assigned to a variable or constant, or when it is passed to a function.
In fact, all of the basic types in Swift - integers, floating-point numbers, Booleans, strings, arrays, and dictionaries - are value types, and are implemented as structures behind the scenes.

All Swift structures are value types. This means that any structure instances you create - and any value types they have as properties - are always copied when they are passed around in your code.

Consider this example, which uses the Resolution structure from the previous example:
let hd = Resolution(width: 1920, height: 1080)
var cinema = hd
Try It Yourself

The example declares a constant called hd and sets it to a Resolution instance.
It then declares a variable called cinema, and sets it to the current value of hd. Because Resolution is a structure, a copy of the existing instance is made, and this new copy is assigned to cinema. Even though hd and cinema now have the same width and height, behind the scenes they are two completely different instances.

Next, the width property of cinema is amended:
cinema.width = 2048Try It Yourself

However, the width property of the original hd instance still has the old value of 1920.
print("hd is still \(hd.width) pixels wide")
// prints "hd is still 1920 pixels wide"
Try It Yourself

The same behavior is true of enumerations.

Classes are Reference Types



Unlike value types, reference types are not copied when assigned to a variable or constant, or when they are passed to a function. Rather than a copy, a reference to the existing instance is used instead.
Here's an example, using the VideoMode class:
let tenEighty = VideoMode()
tenEighty.resolution = hd
tenEighty.interlaced = true

let alsoTenEighty = tenEighty
alsoTenEighty.interlaced = false
Try It Yourself

The video mode is assigned a copy of the hd resolution of 1920 by 1080 from before.
Next, tenEighty is assigned to a new constant, named alsoTenEighty, and the interlaced property of alsoTenEighty is modified.
Because classes are reference types, tenEighty and alsoTenEighty actually both refer to the same VideoMode instance, so the interlaced value is changed for both. Effectively, they are just two different names for the same single instance.
Rather than being declared as variables, tenEighty and alsoTenEighty are declared as constants. However, it's still possible to change their properties, because the values of the tenEighty and alsoTenEighty constants themselves do not actually change.

Identity Operators



You may need to determine whether two constants or variables refer to the same instance of a class. To accomplish this, Swift provides the following identity operators:
Identical to (===)
Not identical to (!==)

Use these operators to check your constants or variables to see if they refer to the same single instance:
if tenEighty === alsoTenEighty {
print("Same")
}
Try It Yourself

Note that "identical to" (represented by three equals signs, or ===) does not mean the same thing as "equal to" (represented by two equals signs, or ==).

Classes vs. Structures



Structure instances are always passed by value, and class instances are always passed by reference. This means that they are suited to different kinds of tasks.
As a general guideline, consider creating a structure instead of a class when one or more of these conditions apply:

1. The structure's primary purpose is to encapsulate a few relatively simple data values.
2. It is reasonable to expect that the encapsulated values will be copied rather than referenced when you assign or pass around an instance of that structure.
3. Any properties stored by the structure are themselves value types, which you would also expect to be copied, as opposed to being referenced.
4. It is not necessary for the structure to inherit properties or behavior from another existing type.

For example, the size of a geometric shape would be a good choice for a structure, with the structure perhaps encapsulating a width property and a height property, both of type Double.

In all other cases, define a class. You will find that most custom data constructs should be defined as classes rather than as structures.
Swift's StringArray, and Dictionary types are implemented as structures.

Properties



Properties associate values with a particular class, structure, or enumerationStored properties store constant and variable values as part of an instance.
In its simplest form, a stored property is a constant or variable that is stored as part of an instance of a particular class or structure.
struct Size {
var width: Int
let height: Int
}
var size1 = Size(width: 10, height: 35)
size1.width = 6
Try It Yourself

In the example above, height is initialized when the new size is created. This is a constant property, and it cannot be changed once initialized.
When creating an instance of a structure, if you assign an instance of a structure to a constant, the instance's properties cannot be modified, even if they were declared as variable properties.

Lazy Stored Properties



lazy stored property's initial value is not calculated until the first time it is used.
class DataManager {
lazy var importer = DataImporter()
var data = [String]()
}
Try It Yourself

Lazy properties are useful when a property's initial value is dependent on outside factors, the values of which are not known until after an instance's initialization is complete; or when the initial value for a property requires complex or computationally expensive setup that should not be performed unless or until it is needed.
You must always declare a lazy property as a variable, using the var keyword, because its initial value might not be retrieved until after the completion of instance initialization. Constant properties must always have a value before initialization completes, and therefore cannot be declared as lazy.

Computed Properties



Rather than storing a value, a computed property provides a getter and, optionally, a setter, which indirectly retrieve and set other properties and values, respectively.
struct Point {
var x = 0.0, y = 0.0
}
struct Shape {
var origin = Point()
var center: Point {
get {
return Point(x: origin.x/2 , y: origin.y/2)
}
set(newCenter) {
origin.x = newCenter.x/2
origin.y = newCenter.y/2
}
}
}
Try It Yourself

The Shape structure defines a custom getter and setter for a computed variable called center. The center property is then accessed through dot syntax, which causes the getter for center to be called to retrieve the current property value. Rather than returning an existing value, the getter actually calculates and returns a new point that represents the center of the shape.

If a computed property's setter does not define a name for the new value to be set, a default name of newValue is used.
Below is an alternative version of the Rect structure, which takes advantage of this shorthand notation:
struct Point {
var x = 0.0, y = 0.0
}
struct Shape {
var origin = Point()
var center: Point {
get {
return Point(x: origin.x/2, y: origin.y/2)
}
set {
origin.x = newValue.x/2
origin.y = newValue.y/2
}
}
}
Try It Yourself

A computed property with a getter but no setter is known as a read-only computed property. It always returns a value, and can be accessed through dot syntax. However, that value cannot be altered.

Property Observers



Property observers detect and respond to changes in a property's value. Property observers are called every time a property's value is set, even if the new value is the same as the property's current value.
Property observers can be added to any defined stored properties, with the exception of lazy stored properties.
You have the option of defining either or both of the following observers of a property:
willSet is called just before the value is stored.
didSet is called immediately after the new value is stored.

The example below defines a new class called StepCounter, which tracks the total number of steps that a person takes while walking.
class StepCounter {
var totalSteps: Int = 0 {
willSet(newSteps) {
print("About to set totalSteps to \(newSteps)")
}
didSet {
if totalSteps > oldValue {
print("Added \(totalSteps - oldValue) steps")
}
}
}
}
let stepCounter = StepCounter()
stepCounter.totalSteps = 50
// About to set totalSteps to 50
// Added 50 steps
stepCounter.totalSteps = 150
// About to set totalSteps to 150
// Added 100 steps
stepCounter.totalSteps = 420
// About to set totalSteps to 420
// Added 270 steps
Try It Yourself

The StepCounter class declares a totalSteps property of type Int, with willSet and didSet observers.
The willSet and didSet observers for totalSteps are called whenever the property is assigned a new value.
The willSet observer uses a custom parameter name of newSteps for the upcoming new value.

The didSet observer is called after the value of totalSteps is updated. It compares the new value of totalSteps against the old value. The didSet observer does not provide a custom parameter name for the old value; the default name of oldValue is used, instead.
Similarly, newValue could be used for the willSet observer, if no parameter name was defined.
If you assign a value to a property within its own didSet observer, the new assigned value will replace the one that was just set.

Type Properties



Type properties are useful when defining values that are universal to all instances of a particular type, such as a constant property used in all instances, or a variable property that stores a global value to all instances of that type. Stored type properties can be variables or constants. You define type properties with the static keyword:
class SomeClass {
static var storedProp = "Some value."
static var computedProp: Int {
return 42
}
}
Try It Yourself

Type properties are queried and set with dot syntax, just like instance properties. However, type properties are queried and set on the type, not on an instance of that type:
print(SomeClass.storedProp) Try It Yourself

Unlike stored instance properties, you must always give stored type properties a default value. This is because the type itself does not have an initializer that can assign a value to a stored type property at initialization time.

Methods



Methods are functions that are associated with a particular type. Classes, structures, and enumerations can all define instance methods.
Instance methods are functions that belong to instances of a particular class, structure, or enumeration. Instance methods have exactly the same syntax as functions:
class Counter {
var count = 0
func increment() {
count+=1
}
func incrementBy(amount: Int) {
count += amount
}
func reset() {
count = 0
}
}
Try It Yourself

You call instance methods with the same dot syntax used for properties:
let counter = Counter()
// the initial counter value is 0
counter.increment()
// the counter's value is now 1
counter.incrementBy(amount: 5)
// the counter's value is now 6
counter.reset()
// the counter's value is now 0
Try It Yourself

Tap Try It Yourself to play around with the code!

The self Property



The self property refers to the current instance within its own instance methods.
The increment() method in the previous example could have been written like this:
func increment() {
self.count+=1
}
Try It Yourself

In practice, you rarely need to write self in your code.
You can use the self property to distinguish between the parameter name and the property name.
Here, self disambiguates between a method parameter called x and an instance property that is also called x:
struct Point {
var x = 0.0, y = 0.0
func isToTheRight(x: Double) -> Bool {
return self.x > x
}
}
Try It Yourself

Without the self prefix, Swift would assume that both uses of x referred to the method parameter called x.

Modifying Value Types



Structures and enumerations are value types. By default, the properties of a value type cannot be modified from within its instance methods.
The mutating keyword is added to the method's definition so it can modify its properties.
struct Point {
var x = 0.0, y = 0.0
mutating func moveByX(dX: Double, dY: Double) {
x += dX
y += dY
}
}
Try It Yourself

You cannot call a mutating method on a constant of structure type, because its properties cannot be changed.
Mutating methods can assign an entirely new instance to the implicit self property.

Type Methods



Instance methods are called on an instance of a particular type. A type method is called on the type itself, and is indicated by writing the keyword static before the method's func keyword:
class SomeClass {
static func someTypeMethod() {
// type method implementation goes here
}
}
SomeClass.someTypeMethod()
Try It Yourself

As with instance methods, type methods are called with dot syntax. However, type methods are called on the type, not on an instance of that type.
Within the body of a type method, the implicit self property refers to the type itself, rather than an instance of that type.

Subscripts



Classes, structures, and enumerations can define subscripts, which are shortcuts for accessing the member elements of a collection, list, or sequence. Subscripts enable you to query instances of a type by writing one or more values in square brackets after the instance name.
Subscript definitions are written using the subscript keyword, and specify one or more input parameters and a return type, in the same way as instance methods.
Here's an example of a read-only subscript implementation, which defines a TimesTable structure to represent an n-times-table of integers:
struct TimesTable {
let multiplier: Int
subscript(index: Int) -> Int {
return multiplier * index
}
}
let threeTimesTable = TimesTable(multiplier: 3)
print(threeTimesTable[5])
// prints "15"
Try It Yourself
Multiple subscripts can be defined for a single type. The appropriate subscript overload to use is selected according to the type of index value you pass to the subscript. Subscripts are not limited to a single dimension, and can be defined using multiple input parameters that best suit your custom type's needs

Subscripts



Matrix is a good example how a subscript is used.
The following example defines a Matrix structure, which represents a two-dimensional matrix of Double values. The subscript takes two integer parameters:
struct Matrix {
let rows: Int, columns: Int
var grid: [Double]
init(rows: Int, columns: Int) {
self.rows = rows
self.columns = columns
grid = Array(repeating: 0.0, count: rows * columns)
}
subscript(row: Int, column: Int) -> Double {
get {
return grid[(row * columns) + column]
}
set {
grid[(row * columns) + column] = newValue
}
}
}
Try It Yourself

Matrix provides an initializer that takes two parameters called rows and columns to create an array large enough to store values of type Double. Each position in the matrix is given an initial value of 0.0.
Initialization is described in detail in the coming lessons.
You can construct a new Matrix instance by passing an appropriate row and column count to its initializer:
var matrix = Matrix(rows: 2, columns: 2)Try It Yourself

This results in the following grid:
Values in the matrix can be set by passing comma-separated row and column values into the subscript.:
matrix[0, 1] = 1.5
matrix[1, 0] = 3.2
Try It Yourself

This results in the following:
Tap Try It Yourself to play around with the code!

Inheritance



A class can inherit methods, properties, and other characteristics from another class. The inheriting class is a subclass, and the class from which it inherits from is its superclass. Inheritance is a fundamental behavior that differentiates classes from other types in Swift.
Any class that does not inherit from another class is known as a base class.
Subclassing is the act of basing a new class on an existing class.
To understand inheritance in action, let's create an example:
class Vehicle {
var currentSpeed = 0.0
var desc: String {
return "traveling at \(currentSpeed) mph"
}
func makeNoise() {
// do nothing
}
}
Try It Yourself

To indicate that a subclass has a superclass, write the subclass name before the superclass name, separated by a colon:
class Bicycle: Vehicle {
var hasBasket = false
}
Try It Yourself

The new Bicycle class automatically takes on all of the characteristics of Vehicle, including properties such as currentSpeed and desc, as well as methods like makeNoise(). In addition to its inherited characteristics, the Bicycle class defines a new stored property, hasBasket.
You can also modify the inherited currentSpeed property of a Bicycle instance, and query the instance's inherited desc property:
let bicycle = Bicycle()
bicycle.hasBasket = true
bicycle.currentSpeed = 25.0
print("Bicycle: \(bicycle.desc)")
Try It Yourself

Subclasses can themselves be subclassed. The next example creates a subclass of Bicycle for a two-seater bicycle, or a tandem.
class Tandem: Bicycle {
var currNumOfPassengers = 0
}
Try It Yourself

If you create an instance of Tandem, you can work with any of its properties, both new and inherited. You can also query the read-only desc property it inherited from Vehicle:
let tandem = Tandem()
tandem.hasBasket = true
tandem.currNumOfPassengers = 2
tandem.currentSpeed = 20.0
print("Tandem: \(tandem.desc)")
Try It Yourself

Tap Try It Yourself to play around with the code!

Overriding



subclass can provide its own custom implementation of an instance method, type methodinstance property, type property, or subscript that it would otherwise inherit from a superclass. This is known as overriding.
To override a characteristic that would otherwise be inherited, prefix the overriding definition with the override keyword.

The superclass version of a method, property, or subscript is accessed by using the super prefix.
For example:
- An overridden method named someMethod() can call the superclass version of someMethod() by calling super.someMethod() within the overriding method implementation.
- An overridden property called someProperty can access the superclass version of someProperty as super.someProperty within the overriding getter or setter implementation.
- An overridden subscript for someIndex can access the superclass version of the same subscript as super[someIndex] from within the overriding subscript implementation.

The following example defines a new subclass of Vehicle, called Train, which overrides the makeNoise() method that Train inherits from Vehicle:
class Train: Vehicle {
override func makeNoise() {
print("Choo Choo")
}
}
Try It Yourself

The following example defines a new class called Car, which is a subclass of Vehicle. The Car class introduces a new stored property called gear, which has a default integer value of 1. The Car class also overrides the description property inherited from Vehicle to provide a custom description that includes the current gear:
class Car: Vehicle {
var gear = 1
override var desc: String {
return super.desc + " in gear \(gear)"
}
}
Try It Yourself

You can prevent a method, property, or subscript override by marking it as final (such as final varfinal funcfinal class func, and final subscript).
You can mark an entire class as final by placing the final modifier before the class keyword in its class definition (final class).

Initialization



The process of preparing an instance of a class, structure, or enumeration for use is called initialization. It involves setting an initial value for each property stored in that instance and performing any other setup or initialization that is required before the new instance is ready for use.
Classes and structures must set all of their stored properties to an appropriate initial value prior to creation of an instance.
Initializers are called to create a new instance of a particular type. In its simplest form, an initializer is like an instance method with no parameters, and is written using the init keyword:
struct Fahrenheit {
var temp: Double
init() {
temp = 32.0
}
}
var f = Fahrenheit()
Try It Yourself

As part of an initializer's definition, initialization parameters define the types and names of values that customize the initialization process.
struct Celsius {
var tempInCelsius: Double
init(fromFahrenheit fahrenheit: Double) {
tempInCelsius = (fahrenheit - 32.0) / 1.8
}
init(fromKelvin kelvin: Double) {
tempInCelsius = kelvin - 273.15
}
}
let boilingPoint = Celsius(fromFahrenheit: 212.0)
let freezingPoint = Celsius(fromKelvin: 273.15)
Try It Yourself

The example above defines a structure called Celsius, which implements two custom initializers called init(fromFahrenheit:) and init(fromKelvin:). This initializes a new instance of the structure with a value from a different temperature scale.
When you assign a default value to a stored property, or set its initial value within an initializer, the value of that property is set directly, without calling any property observers.

Initializers



In the case of structure types that have no defined custom initializers, Swift automatically provides a memberwise initializer, even if the structure types have stored properties that do not have default values.
The Size structure automatically receives an init(width:height:) memberwise initializer, which you can use to initialize a new Size instance:
struct Size {
var width = 0.0, height = 0.0
}
let twoByTwo = Size(width: 2.0, height: 2.0)
Try It Yourself

Class Initialization



All stored properties of a class - including any properties inherited from its superclass - must be assigned an initial value during initialization. In other words, assign a default value or create an initializer for the properties of the class.
The structure from the above example would have the following form as a class with an initializer:
class Size {
var width:Double, height:Double
init(w:Double, h:Double) {
width = w
height = h
}
}
let twoByTwo = Size(w: 2.0, h: 2.0)
Try It Yourself

Tap Try It Yourself to play around with the code!

Required Initializers



Write the required modifier before the definition of a class initializer to indicate that every subclass of the class must implement that initializer:
class SomeClass {
required init() {
// initializer implementation goes here
}
}
Try It Yourself

You must also insert the required modifier before every subclass implementation of a required initializer. This indicates that the initializer requirement applies to further subclasses along the chain. Do not write the override modifier when overriding a required designated initializer:
class SomeSubclass: SomeClass {
required init() {
// subclass implementation goes here
}
}
Try It Yourself

It's not necessary to provide an explicit implementation of a required initializer if you can satisfy the requirement with an inherited initializer.

Deinitialization



deinitializer is called immediately before a class instance is deallocated, and is useful when you work with your own resources.
For example, if you create a custom class to open a file and write some data to it, you might need to close the file before the class instance is deallocated.
Class definitions can have at most one deinitializer per class.
Rather than providing you with the ability to call a deinitializer, Swift automatically calls it, just prior to instance deallocation. Superclass deinitializers are inherited by their subclasses, and the superclass deinitializer is called automatically at the end of a subclass deinitializer implementation. Superclass deinitializers are always called, even in cases in which subclasses do not provide their own deinitializers.

The deinit keyword is used to write a deinitializer, which is similar to writing an initializer using the init keyword. The deinitializer does not take any parameters and is written with no parentheses:
deinit {
// perform the deinitialization
}
Try It Yourself

Deinitializers are only available on class types.

No comments:

Post a Comment