Swift Chapter 7 2018-12-19T13:11:06+00:00

SWIFT CHAPTER 7

Topics:(Optional Chaining, Error Handling, Type Casting, Nested Types, Extensions)

Optional Chaining

Optional chaining is a process for querying and calling properties, methods, and subscripts on an optional that might currently be nil. If the optional contains a value, the property, method, or subscript call succeeds; if the optional is nil, the property, method, or subscript call returns nil. Multiple queries can be chained together, and the entire chain fails gracefully if any link in the chain is nil.

Optional Chaining as an Alternative to Forced Unwrapping

You specify optional chaining by placing a question mark (?) after the optional value on which you wish to call a property, method or subscript if the optional is non-nil. This is very similar to placing an exclamation mark (!) after an optional value to force the unwrapping of its value. The main difference is that optional chaining fails gracefully when the optional is nil, whereas forced unwrapping triggers a runtime error when the optional is nil.
To reflect the fact that optional chaining can be called on a nil value, the result of an optional chaining call is always an optional value, even if the property, method, or subscript you are querying returns a nonoptional value. You can use this optional return value to check whether the optional chaining call was successful (the returned optional contains a value), or did not succeed due to a nil value in the chain (the returned optional value is nil).
Specifically, the result of an optional chaining call is of the same type as the expected return value, but wrapped in an optional. A property that normally returns an Int will return an Int? when accessed through optional chaining.
The next several code snippets demonstrate how optional chaining differs from forced unwrapping and enables you to check for success.
First, two classes called Person and Residence are defined:

class Person {
var residence: ?
}

class Residence {
var numberOfRooms = 1
}
Residence instances have a single Int property called numberOfRooms, with a default value of 1. Person instances have an optional residence property of type Residence?.If you create a new Person instance, its residence property is default initialized to nil, by virtue of being optional. In the code below, john has a residence property value of nil:

let john = Person()

If you try to access the numberOfRooms property of this person’s residence, by placing an exclamation mark after residence to force the unwrapping of its value, you trigger a runtime error, because there is no residence value to unwrap:

let roomCount = john.residence!.numberOfRooms
// this triggers a runtime error

The code above succeeds when john.residence has a non-nil value and will set roomCount to an Int value containing the appropriate number of rooms. However, this code always triggers a runtime error when residence is nil, as illustrated above.
Optional chaining provides an alternative way to access the value of numberOfRooms. To use optional chaining, use a question mark in place of the exclamation mark:

if let roomCount = john.residence?.numberOfRooms {
print(“John’s residence has \(roomCount) room(s).”)
} else {
print(“Unable to retrieve the number of rooms.”)
}  // Prints “Unable to retrieve the number of rooms.”

This tells Swift to “chain” on the optional residence property and to retrieve the value of numberOfRooms if residence exists.Because the attempt to access numberOfRooms has the potential to fail, the optional chaining attempt returns a value of type Int?, or “optional Int”. When residence is nil, as in the example above, this optional Int will also be nil, to reflect the fact that it was not possible to access numberOfRooms. The optional Int is accessed through optional binding to unwrap the integer and assign the non-optional value to the roomCount variable.
Note that this is true even though numberOfRooms is a nonoptional Int. The fact that it is queried through an optional chain means that the call to numberOfRooms will always return an Int? instead of an Int.You can assign a Residence instance to john.residence, so that it no longer has a nil value:

john.residence = Residence()

john.residence now contains an actual Residence instance, rather than nil. If you try to access numberOfRooms with the same optional chaining as before, it will now return an Int? that contains the default numberOfRooms value of 1:

if let roomCount = john.residence?.numberOfRooms {
print(“John’s residence has \(roomCount) room(s).”)
} else {
print(“Unable to retrieve the number of rooms.”)
}
// Prints “John’s residence has 1 room(s).”


Defining Model Classes for Optional Chaining

You can use optional chaining with calls to properties, methods, and subscripts that are more than one level deep. This enables you to drill down into sub-properties within complex models of interrelated types, and to check whether it is possible to access properties, methods, and subscripts on those subproperties.
The code snippets below define four model classes for use in several subsequent examples, including examples of multilevel optional chaining. These classes expand upon the Person and Residence model from above by adding a Room and Address class, with associated properties, methods, and subscripts.
The Person class is defined in the same way as before:

class Person {
var residence: ?
}
The Residence class is more complex than before. This time, the Residence class defines a variable property called rooms, which is initialized with an empty array of type [Room]:

class Residence {
var rooms = [Room]()
var numberOfRooms: {
return rooms.count
}
subscript(i: ) -> {
get {
return rooms[i] }
set {
rooms[i] = newValue
}
}
func printNumberOfRooms() {
print(“The number of rooms is \(numberOfRooms)”)
}
var address: ?
}

Because this version of Residence stores an array of Room instances, its numberOfRooms property is implemented as a computed property, not a stored property. The computed numberOfRooms property simply returns the value of the count property from the rooms array.As a shortcut to accessing its rooms array, this version of Residence provides a read-write subscript that provides access to the room at the requested index in the rooms array.
This version of Residence also provides a method called printNumberOfRooms, which simply prints the number of rooms in the residence.
Finally, Residence defines an optional property called address, with a type of Address?. The Address class type for this property is defined below.
The Room class used for the rooms array is a simple class with one property called name, and an initializer to set that property to a suitable room name:

class Room {
let name:
init(name: ) { self.name = name }
}
The final class in this model is called Address. This class has three optional properties of type String?. The first two properties, buildingName and buildingNumber, are alternative ways to identify a particular building as part of an address. The third property, street, is used to name the street for that address:

class Address {
var buildingName: ?
var buildingNumber: ?
var street: ?
func buildingIdentifier() -> ? {
if let buildingNumber = buildingNumber, let street = street {
return “\(buildingNumber) \(street)”
} else if buildingName != nil {
return buildingName
} else {
return nil
}
}
}

The Address class also provides a method called buildingIdentifier(), which has a return type of String?. This method checks the properties of the address and returns buildingName if it has a value, or buildingNumber concatenated with street if both have values, or nil otherwise.

‌Accessing Properties Through Optional Chaining

As demonstrated in Optional Chaining as an Alternative to Forced Unwrapping, you can use optional chaining to access a property on an optional value, and to check if that property access is successful.
Use the classes defined above to create a new Person instance, and try to access its numberOfRooms property as before:

let john = Person()
if let roomCount = john.residence?.numberOfRooms {
print(“John’s residence has \(roomCount) room(s).”)
} else {
print(“Unable to retrieve the number of rooms.”)
}
// Prints “Unable to retrieve the number of rooms.”

Because john.residence is nil, this optional chaining call fails in the same way as before.
You can also attempt to set a property’s value through optional chaining:

let someAddress = Address()
someAddress.buildingNumber = “29”
someAddress.street = “Acacia Road”
john.residence?.address = someAddress

In this example, the attempt to set the address property of john.residence will fail, because john.residence is currently nil.
The assignment is part of the optional chaining, which means none of the code on the right-hand side of the = operator is evaluated. In the previous example, it’s not easy to see that someAddress is never evaluated, because accessing a constant doesn’t have any side effects. The listing below does the same assignment, but it uses a function to create the address. The function prints “Function was called” before returning a value, which lets you see whether the right-hand side of the = operator was evaluated.

func createAddress() -> {
print(“Function was called.”)

let someAddress = Address()
someAddress.buildingNumber = “29”
someAddress.street = “Acacia Road”

return someAddress
}
john.residence?.address = createAddress()

You can tell that the createAddress() function isn’t called, because nothing is printed.

‌Calling Methods Through Optional Chaining

You can use optional chaining to call a method on an optional value, and to check whether that method call is successful. You can do this even if that method does not define a return value.The printNumberOfRooms() method on the Residence class prints the current value of numberOfRooms. Here’s how the method looks:

func printNumberOfRooms() {
print(“The number of rooms is \(numberOfRooms)”)
}
This method does not specify a return type. However, functions and methods with no return type have an implicit return type of Void, as described in Functions Without Return Values. This means that they return a value of (), or an empty tuple.If you call this method on an optional value with optional chaining, the method’s return type will be Void?, not Void, because return values are always of an optional type when called through optional chaining. This enables you to use an if statement to check whether it was possible to call the printNumberOfRooms() method, even though the method does not itself define a return value. Compare the return value from the printNumberOfRooms call against nil to see if the method call was successful:

if john.residence?.printNumberOfRooms() != nil {
print(“It was possible to print the number of rooms.”)
} else {
print(“It was not possible to print the number of rooms.”)
}     // Prints “It was not possible to print the number of rooms.”

The same is true if you attempt to set a property through optional chaining. The example above in Accessing Properties Through Optional Chaining attempts to set an address value for john.residence, even though the residence property is nil. Any attempt to set a property through optional chaining returns a value of type Void?, which enables you to compare against nil to see if the property was set successfully:

if (john.residence?.address = someAddress) != nil {
print(“It was possible to set the address.”)
} else {
print(“It was not possible to set the address.”)
}
// Prints “It was not possible to set the address.”

‌Accessing Subscripts Through Optional Chaining

You can use optional chaining to try to retrieve and set a value from a subscript on an optional value, and to check whether that subscript call is successful.When you access a subscript on an optional value through optional chaining, you place the question mark before the subscript’s brackets, not after. The optional chaining question mark always follows immediately after the part of the expression that is optional.

The example below tries to retrieve the name of the first room in the rooms array of the john.residence property using the subscript defined on the Residence class. Because john.residence is currently nil, the subscript call fails:

if let firstRoomName = john.residence?[0].name {
print(“The first room name is \(firstRoomName).”)
} else {
print(“Unable to retrieve the first room name.”)
}               // Prints “Unable to retrieve the first room name.”

The optional chaining question mark in this subscript call is placed immediately after john.residence, before the subscript brackets, because john.residence is the optional value on which optional chaining is being attempted.
Similarly, you can try to set a new value through a subscript with optional chaining:

john.residence?[0] = Room(name: “Bathroom”)

This subscript setting attempt also fails, because residence is currently nil.If you create and assign an actual Residence instance to john.residence, with one or more Room instances in its rooms array, you can use the Residence subscript to access the actual items in the rooms array through optional chaining:

let johnsHouse = Residence()
johnsHouse.rooms.append(Room(name: “Living Room”))
johnsHouse.rooms.append(Room(name: “Kitchen”))
john.residence = johnsHouse

if let firstRoomName = john.residence?[0].name {
print(“The first room name is \(firstRoomName).”)
} else {
print(“Unable to retrieve the first room name.”)
}
// Prints “The first room name is Living Room.”

Accessing Subscripts of Optional Type

If a subscript returns a value of optional type—such as the key subscript of Swift’s Dictionary type—place a question mark after the subscript’s closing bracket to chain on its optional return value:

var testScores = [“Dave”: [86, 82, 84], “Bev”: [79, 94, 81]]
testScores[“Dave”]?[0] = 91
testScores[“Bev”]?[0] += 1
testScores[“Brian”]?[0] = 72
// the “Dave” array is now [91, 82, 84] and the “Bev” array is now [80, 94, 81]

The example above defines a dictionary called testScores, which contains two key-value pairs that map a String key to an array of Int values. The example uses optional chaining to set the first item in the “Dave” array to 91; to increment the first item in the “Bev” array by 1; and to try to set the first item in an array for a key of “Brian”. The first two calls succeed, because the testScores dictionary contains keys for “Dave” and “Bev”. The third call fails, because the testScores dictionary does not contain a key for “Brian”.

‌Linking Multiple Levels of Chaining

You can link together multiple levels of optional chaining to drill down to properties, methods, and subscripts deeper within a model. However, multiple levels of optional chaining do not add more levels of optionality to the returned value.
To put it another way:
If the type you are trying to retrieve is not optional, it will become optional because of the optional chaining.
If the type you are trying to retrieve is already optional, it will not become more optional because of the chaining.
Therefore:
If you try to retrieve an Int value through optional chaining, an Int? is always returned, no matter how many levels of chaining are used.Similarly, if you try to retrieve an Int? value through optional chaining, an Int? is always returned, no matter how many levels of chaining are used.The example below tries to access the street property of the address property of the residence property of john. There are two levels of optional chaining in use here, to chain through the residence and address properties, both of which are of optional type:

if let johnsStreet = john.residence?.address?.street {
print(“John’s street name is \(johnsStreet).”)
} else {
print(“Unable to retrieve the address.”)
}         // Prints “Unable to retrieve the address.”

The value of john.residence currently contains a valid Residence instance. However, the value of john.residence.address is currently nil. Because of this, the call to john.residence?.address?.street fails.Note that in the example above, you are trying to retrieve the value of the street property. The type of this property is String?. The return value of john.residence?.address?.street is therefore also String?, even though two levels of optional chaining are applied in addition to the underlying optional type of the property.
If you set an actual Address instance as the value for john.residence.address, and set an actual value for the address’s street property, you can access the value of the street property through multilevel optional chaining:

let johnsAddress = Address()
johnsAddress.buildingName = “The Larches”
johnsAddress.street = “Laurel Street”
john.residence?.address = johnsAddress

if let johnsStreet = john.residence?.address?.street {
print(“John’s street name is \(johnsStreet).”)
} else {
print(“Unable to retrieve the address.”)
}
// Prints “John’s street name is Laurel Street.”

In this example, the attempt to set the address property of john.residence will succeed, because the value of john.residence currently contains a valid Address instance.

Chaining on Methods with Optional Return Values

The previous example shows how to retrieve the value of a property of optional type through optional chaining. You can also use optional chaining to call a method that returns a value of optional type, and to chain on that method’s return value if needed.
The example below calls the Address class’s buildingIdentifier() method through optional chaining. This method returns a value of type String?. As described above, the ultimate return type of this method call after optional chaining is also String?:

if let buildingIdentifier = john.residence?.address?.buildingIdentifier() {
print(“John’s building identifier is \(buildingIdentifier).”)
}              // Prints “John’s building identifier is The Larches.”

If you want to perform further optional chaining on this method’s return value, place the optional chaining question mark after the method’s parentheses:

if let beginsWithThe =
john.residence?.address?.buildingIdentifier()?.hasPrefix(“The”) {
if beginsWithThe {
print(“John’s building identifier begins with \”The\”.”)
} else {
print(“John’s building identifier does not begin with \”The\”.”)
}
}
// Prints “John’s building identifier begins with “The”.”

In the example above, you place the optional chaining question mark after the parentheses, because the optional value you are chaining on is the buildingIdentifier() method’s return value, and not the buildingIdentifier() method itself.

Error Handling

Error handling is the process of responding to and recovering from error conditions in your program. Swift provides first-class support for throwing, catching, propagating, and manipulating recoverable errors at runtime.Some operations aren’t guaranteed to always complete execution or produce a useful output. Optionals are used to represent the absence of a value, but when an operation fails, it’s often useful to understand what caused the failure, so that your code can respond accordingly.
As an example, consider the task of reading and processing data from a file on disk. There are a number of ways this task can fail, including the file not existing at the specified path, the file not having read permissions, or the file not being encoded in a compatible format. Distinguishing among these different situations allows a program to resolve some errors and to communicate to the user any errors it can’t resolve.

Representing and Throwing Errors

In Swift, errors are represented by values of types that conform to the Error protocol. This empty protocol indicates that a type can be used for error handling.Swift enumerations are particularly well suited to modeling a group of related error conditions, with associated values allowing for additional information about the nature of an error to be communicated. For example, here’s how you might represent the error conditions of operating a vending machine inside a game:

enum VendingMachineError: {
case invalidSelection
case insufficientFunds(coinsNeeded: Int)
case outOfStock
}
Throwing an error lets you indicate that something unexpected happened and the normal flow of execution can’t continue. You use a throw statement to throw an error. For example, the following code throws an error to indicate that five additional coins are needed by the vending machine:

throw VendingMachineError.insufficientFunds(coinsNeeded: 5)

‌Handling Errors

When an error is thrown, some surrounding piece of code must be responsible for handling the error—for example, by correcting the problem, trying an alternative approach, or informing the user of the failure.
There are four ways to handle errors in Swift. You can propagate the error from a function to the code that calls that function, handle the error using a do-catch statement, handle the error as an optional value, or assert that the error will not occur. Each approach is described in a section below.
When a function throws an error, it changes the flow of your program, so it’s important that you can quickly identify places in your code that can throw errors. To identify these places in your code, write the try keyword—or the try? or try! variation—before a piece of code that calls a function, method, or initializer that can throw an error. These keywords are described in the sections below.

Propagating Errors Using Throwing Functions

To indicate that a function, method, or initializer can throw an error, you write the throws keyword in the function’s declaration after its parameters. A function marked with throws is called a throwing function. If the function specifies a return type, you write the throws keyword before the return arrow (->).

func canThrowErrors() throws ->

func cannotThrowErrors() ->

A throwing function propagates errors that are thrown inside of it to the scope from which it’s called.Only throwing functions can propagate errors. Any errors thrown inside a nonthrowing function must be handled inside the function.

In the example below, the VendingMachine class has a vend(itemNamed:) method that throws an appropriate VendingMachineError if the requested item is not available, is out of stock, or has a cost that exceeds the current deposited amount:

struct Item {

    var price:

    var count:

}

class VendingMachine {

    var inventory = [

        “Candy Bar”: Item(price: 12, count: 7),

        “Chips”: Item(price: 10, count: 4),

        “Pretzels”: Item(price: 7, count: 11)

    ]

    var coinsDeposited = 0

     func vend(itemNamed name: ) throws {

        guard let item = inventory[name] else {

            throw VendingMachineError.invalidSelection

        }

           guard item.count > 0 else {

            throw VendingMachineError.outOfStock

        }

          guard item.price <= coinsDeposited else {

            throw VendingMachineError.insufficientFunds(coinsNeeded: item.pricecoinsDeposited)

        }

        coinsDeposited -= item.price

        var newItem = item

        newItem.count -= 1

        inventory[name] = newItem

         print(“Dispensing \(name))

    }

}

The implementation of the vend(itemNamed:) method uses guard statements to exit the method early and throw appropriate errors if any of the requirements for purchasing a snack aren’t met. Because a throw statement immediately transfers program control, an item will be vended only if all of these requirements are met.

Because the vend(itemNamed:) method propagates any errors it throws, any code that calls this method must either handle the errors—using a docatch statement, try?, or try!—or continue to propagate them. For example, the buyFavoriteSnack(person:vendingMachine:) in the example below is also a throwing function, and any errors that the vend(itemNamed:) method throws will propagate up to the point where the buyFavoriteSnack(person:vendingMachine:) function is called.

let favoriteSnacks = [

    “Alice”: “Chips”,

    “Bob”: “Licorice”,

    “Eve”: “Pretzels”,

]

func buyFavoriteSnack(person: , vendingMachine: ) throws {

    let snackName = favoriteSnacks[person] ?? “Candy Bar”

    try vendingMachine.vend(itemNamed: snackName)

}

In this example, the buyFavoriteSnack(person: vendingMachine:) function looks up a given person’s favorite snack and tries to buy it for them by calling the vend(itemNamed:) method. Because the vend(itemNamed:) method can throw an error, it’s called with the try keyword in front of it.

Throwing initializers can propagate errors in the same way as throwing functions. For example, the initializer for the PurchasedSnack structure in the listing below calls a throwing function as part of the initialization process, and it handles any errors that it encounters by propagating them to its caller.

struct PurchasedSnack {

    let name:

    init(name: , vendingMachine: ) throws {

        try vendingMachine.vend(itemNamed: name)

        self.name = name

    }

}

Handling Errors Using Do-Catch

You use a docatch statement to handle errors by running a block of code. If an error is thrown by the code in the do clause, it is matched against the catch clauses to determine which one of them can handle the error.

Here is the general form of a docatch statement:

do {

    try expression

    statements

} catch pattern 1 {

    statements

} catch pattern 2 where condition {

    statements

}

You write a pattern after catch to indicate what errors that clause can handle. If a catch clause doesn’t have a pattern, the clause matches any error and binds the error to a local constant named errorThe catch clauses don’t have to handle every possible error that the code in its do clause can throw. If none of the catch clauses handle the error, the error propagates to the surrounding scope. However, the error must be handled by some surrounding scope—either by an enclosing docatch clause that handles the error or by being inside a throwing function. For example, the following code handles all three cases of the VendingMachineError enumeration, but all other errors have to be handled by its surrounding scope:

var vendingMachine = VendingMachine()

vendingMachine.coinsDeposited = 8

do {

    try buyFavoriteSnack(person: “Alice”, vendingMachine: vendingMachine)

} catch VendingMachineError.invalidSelection {

    print(“Invalid Selection.”)

} catch VendingMachineError.outOfStock {

    print(“Out of Stock.”)

} catch VendingMachineError.insufficientFunds(let coinsNeeded) {

    print(“Insufficient funds. Please insert an additional \(coinsNeeded) coins.”)

}        // Prints “Insufficient funds. Please insert an additional 2 coins.”

In the above example, the buyFavoriteSnack(person:vendingMachine:) function is called in a try expression, because it can throw an error. If an error is thrown, execution immediately transfers to the catch clauses, which decide whether to allow propagation to continue. If no error is thrown, the remaining statements in the do statement are executed.

Converting Errors to Optional Values

You use try? to handle an error by converting it to an optional value. If an error is thrown while evaluating the try? expression, the value of the expression is nil. For example, in the following code x and y have the same value and behavior:

func someThrowingFunction() throws ->  {

    // …

}

let x = try? someThrowingFunction()

let y: ?

do {

    y = try someThrowingFunction()

} catch {

    y = nil

}

If someThrowingFunction() throws an error, the value of x and y is nil. Otherwise, the value of x and y is the value that the function returned. Note that x and y are an optional of whatever type someThrowingFunction() returns. Here the function returns an integer, so x and y are optional integers.
Using try? lets you write concise error handling code when you want to handle all errors in the same way. For example, the following code uses several approaches to fetch data, or returns nil if all of the approaches fail.

func fetchData() -> ? {
if let data = try? fetchDataFromDisk() { return data }
if let data = try? fetchDataFromServer() { return data }
return nil
}


Disabling Error Propagation

Sometimes you know a throwing function or method won’t, in fact, throw an error at runtime. On those occasions, you can write try! before the expression to disable error propagation and wrap the call in a runtime assertion that no error will be thrown. If an error actually is thrown, you’ll get a runtime error.
For example, the following code uses a loadImage(atPath:) function, which loads the image resource at a given path or throws an error if the image can’t be loaded. In this case, because the image is shipped with the application, no error will be thrown at runtime, so it is appropriate to disable error propagation.

let photo = try! loadImage(atPath: “./Resources/John Appleseed.jpg”)


Specifying Cleanup Actions

You use a defer statement to execute a set of statements just before code execution leaves the current block of code. This statement lets you do any necessary cleanup that should be performed regardless of how execution leaves the current block of code—whether it leaves because an error was thrown or because of a statement such as return or break. For example, you can use a defer statement to ensure that file descriptors are closed and manually allocated memory is freed.
A defer statement defers execution until the current scope is exited. This statement consists of the defer keyword and the statements to be executed later. The deferred statements may not contain any code that would transfer control out of the statements, such as a break or a return statement, or by throwing an error. Deferred actions are executed in the reverse of the order that they’re written in your source code. That is, the code in the first defer statement executes last, the code in the second defer statement executes second to last, and so on. The last defer statement in source code order executes first.

func processFile(filename: ) throws {
if exists(filename) {
let file = open(filename)
defer {
close(file)
}
while let line = try file.readline() {
// Work with the file.
}
// close(file) is called here, at the end of the scope.
}
}

The above example uses a defer statement to ensure that the open(_:) function has a corresponding call to close(_:).You can use a defer statement even when no error handling code is involved.

Type Casting

Type casting is a way to check the type of an instance, or to treat that instance as a different superclass or subclass from somewhere else in its own class hierarchy.Type casting in Swift is implemented with the is and as operators. These two operators provide a simple and expressive way to check the type of a value or cast a value to a different type.You can also use type casting to check whether a type conforms to a protocol. ‌

Defining a Class Hierarchy for Type Casting

You can use type casting with a hierarchy of classes and subclasses to check the type of a particular class instance and to cast that instance to another class within the same hierarchy. The three code snippets below define a hierarchy of classes and an array containing instances of those classes, for use in an example of type casting.
The first snippet defines a new base class called MediaItem. This class provides basic functionality for any kind of item that appears in a digital media library. Specifically, it declares a name property of type String, and an init name initializer. (It is assumed that all media items, including all movies and songs, will have a name.)

class MediaItem {
var name:
init(name: ) {
self.name = name
}
}
The next snippet defines two subclasses of MediaItem. The first subclass, Movie, encapsulates additional information about a movie or film. It adds a director property on top of the base MediaItem class, with a corresponding initializer. The second subclass, Song, adds an artist property and initializer on top of the base class:

class Movie: {
var director:
init(name: , director: ) {
self.director = director
super.init(name: name)
}
}

class Song: {
var artist:
init(name: , artist: ) {
self.artist = artist
super.init(name: name)
}
}
The final snippet creates a constant array called library, which contains two Movie instances and three Song instances. The type of the library array is inferred by initializing it with the contents of an array literal. Swift’s type checker is able to deduce that Movie and Song have a common superclass of MediaItem, and so it infers a type of [MediaItem] for the library array:

let library = [
Movie(name: “Casablanca”, director: “Michael Curtiz”),
Song(name: “Blue Suede Shoes”, artist: “Elvis Presley”),
Movie(name: “Citizen Kane”, director: “Orson Welles”),
Song(name: “The One And Only”, artist: “Chesney Hawkes”),
Song(name: “Never Gonna Give You Up”, artist: “Rick Astley”)
]
// the type of “library” is inferred to be [MediaItem]

The items stored in library are still Movie and Song instances behind the scenes. However, if you iterate over the contents of this array, the items you receive back are typed as MediaItem, and not as Movie or Song. In order to work with them as their native type, you need to check their type, or downcast them to a different type, as described below.

Checking Type

Use the type check operator (is) to check whether an instance is of a certain subclass type. The type check operator returns true if the instance is of that subclass type and false if it is not.
The example below defines two variables, movieCount and songCount, which count the number of Movie and Song instances in the library array:

var movieCount = 0
var songCount = 0for item in library {
if item is {
movieCount += 1
} else if item is {
songCount += 1
}
}print(“Media library contains \(movieCount) movies and \(songCount) songs”)
// Prints “Media library contains 2 movies and 3 songs”

This example iterates through all items in the library array. On each pass, the for-in loop sets the item constant to the next MediaItem in the array.
item is Movie returns true if the current MediaItem is a Movie instance and false if it is not. Similarly, item is Song checks whether the item is a Song instance. At the end of the for-in loop, the values of movieCount and songCount contain a count of how many MediaItem instances were found of each type.

‌Downcasting

A constant or variable of a certain class type may actually refer to an instance of a subclass behind the scenes. Where you believe this is the case, you can try to downcast to the subclass type with a type cast operator (as? or as!).Because downcasting can fail, the type cast operator comes in two different forms. The conditional form, as?, returns an optional value of the type you are trying to downcast to. The forced form, as!, attempts the downcast and force-unwraps the result as a single compound action.
Use the conditional form of the type cast operator (as?) when you are not sure if the downcast will succeed. This form of the operator will always return an optional value, and the value will be nil if the downcast was not possible. This enables you to check for a successful downcast.Use the forced form of the type cast operator (as!) only when you are sure that the downcast will always succeed. This form of the operator will trigger a runtime error if you try to downcast to an incorrect class type.
The example below iterates over each MediaItem in library, and prints an appropriate description for each item. To do this, it needs to access each item as a true Movie or Song, and not just as a MediaItem. This is necessary in order for it to be able to access the director or artist property of a Movie or Song for use in the description.In this example, each item in the array might be a Movie, or it might be a Song. You don’t know in advance which actual class to use for each item, and so it is appropriate to use the conditional form of the type cast operator (as?) to check the downcast each time through the loop:

for item in library {
if let movie = item as? {
print(“Movie: \(movie.name), dir. \(movie.director)”)
} else if let song = item as? {
print(“Song: \(song.name), by \(song.artist)”)
}
}// Movie: Casablanca, dir. Michael Curtiz
// Song: Blue Suede Shoes, by Elvis Presley
// Movie: Citizen Kane, dir. Orson Welles
// Song: The One And Only, by Chesney Hawkes
// Song: Never Gonna Give You Up, by Rick Astley

The example starts by trying to downcast the current item as a Movie. Because item is a MediaItem instance, it’s possible that it might be a Movie; equally, it’s also possible that it might be a Song, or even just a base MediaItem. Because of this uncertainty, the as? form of the type cast operator returns an optional value when attempting to downcast to a subclass type. The result of item as? Movie is of type Movie?, or “optional Movie”.
Downcasting to Movie fails when applied to the Song instances in the library array. To cope with this, the example above uses optional binding to check whether the optional Movie actually contains a value (that is, to find out whether the downcast succeeded.) This optional binding is written “if let movie = item as? Movie”, which can be read as:
“Try to access item as a Movie. If this is successful, set a new temporary constant called movie to the value stored in the returned optional Movie.”
If the downcasting succeeds, the properties of movie are then used to print a description for that Movie instance, including the name of its director. A similar principle is used to check for Song instances, and to print an appropriate description (including artist name) whenever a Song is found in the library.Casting does not actually modify the instance or change its values. The underlying instance remains the same; it is simply treated and accessed as an instance of the type to which it has been cast.

‌Type Casting for Any and AnyObject

Swift provides two special types for working with nonspecific types:
Any can represent an instance of any type at all, including function types.
AnyObject can represent an instance of any class type.
Use Any and AnyObject only when you explicitly need the behavior and capabilities they provide. It is always better to be specific about the types you expect to work with in your code.Here’s an example of using Any to work with a mix of different types, including function types and nonclass types. The example creates an array called things, which can store values of type Any:

var things = [Any]()

things.append(0)
things.append(0.0)
things.append(42)
things.append(3.14159)
things.append(“hello”)
things.append((3.0, 5.0))
things.append(Movie(name: “Ghostbusters”, director: “Ivan Reitman”))
things.append({ (name: ) -> in “Hello, \(name)” })

The things array contains two Int values, two Double values, a String value, a tuple of type (Double, Double), the movie “Ghostbusters”, and a closure expression that takes a String value and returns another String value.
To discover the specific type of a constant or variable that is known only to be of type Any or AnyObject, you can use an is or as pattern in a switch statement’s cases. The example below iterates over the items in the things array and queries the type of each item with a switch statement. Several of the switch statement’s cases bind their matched value to a constant of the specified type to enable its value to be printed:

for thing in things {
switch thing {
case 0 as :
print(“zero as an Int”)
case 0 as :
print(“zero as a Double”)
case let someInt as :
print(“an integer value of \(someInt)”)
case let someDouble as where someDouble > 0:
print(“a positive double value of \(someDouble)”)
case is :
print(“some other double value that I don’t want to print”)
case let someString as :
print(“a string value of \”\(someString)\””)
case let (x, y) as (, ):
print(“an (x, y) point at \(x), \(y)”)
case let movie as :
print(“a movie called \(movie.name), dir. \(movie.director)”)
case let stringConverter as () -> :
print(stringConverter(“Michael”))
default:
print(“something else”)
}
}// zero as an Int
// zero as a Double
// an integer value of 42
// a positive double value of 3.14159
// a string value of “hello”
// an (x, y) point at 3.0, 5.0
// a movie called Ghostbusters, dir. Ivan Reitman
// Hello, Michael

The Any type represents values of any type, including optional types. Swift gives you a warning if you use an optional value where a value of type Any is expected. If you really do need to use an optional value as an Any value, you can use the as operator to explicitly cast the optional to Any, as shown below.

let optionalNumber: ? = 3
things.append(optionalNumber) // Warning
things.append(optionalNumber as Any) // No warning

Nested Types

Enumerations are often created to support a specific class or structure’s functionality. Similarly, it can be convenient to define utility classes and structures purely for use within the context of a more complex type. To accomplish this, Swift enables you to define nested types, whereby you nest supporting enumerations, classes, and structures within the definition of the type they support.To nest a type within another type, write its definition within the outer braces of the type it supports. Types can be nested to as many levels as are required.

Nested Types in Action

The example below defines a structure called BlackjackCard, which models a playing card as used in the game of Blackjack. The BlackjackCard structure contains two nested enumeration types called Suit and Rank.
In Blackjack, the Ace cards have a value of either one or eleven. This feature is represented by a structure called Values, which is nested within the Rank enumeration:

struct BlackjackCard {
// nested Suit enumeration
enum Suit: {
case spades = “♠”, hearts = “♡”, diamonds = “♢”, clubs = “♣”
}
// nested Rank enumeration
enum Rank: {
case two = 2, three, four, five, six, seven, eight, nine, ten
case jack, queen, king, ace
struct Values {
let first: , second: ?
}
var values: {
switch self {
case .ace:
return Values(first: 1, second: 11)
case .jack, .queen, .king:
return Values(first: 10, second: nil)
default:
return Values(first: self.rawValue, second: nil)
}
}
}
// BlackjackCard properties and methods
let rank: , suit:
var description: {
var output = “suit is \(suit.rawValue),”
output += ” value is \(rank.values.first)”
if let second = rank.values.second {
output += ” or \(second)”
}
return output
}
}

The Suit enumeration describes the four common playing card suits, together with a raw Character value to represent their symbol.The Rank enumeration describes the thirteen possible playing card ranks, together with a raw Int value to represent their face value. (This raw Int value is not used for the Jack, Queen, King, and Ace cards.)
As mentioned above, the Rank enumeration defines a further nested structure of its own, called Values. This structure encapsulates the fact that most cards have one value, but the Ace card has two values. The Values structure defines two properties to represent this:
first, of type Int
second, of type Int?, or “optional Int”
Rank also defines a computed property, values, which returns an instance of the Values structure. This computed property considers the rank of the card and initializes a new Values instance with appropriate values based on its rank. It uses special values for jack, queen, king, and ace. For the numeric cards, it uses the rank’s raw Int value.
The BlackjackCard structure itself has two properties—rank and suit. It also defines a computed property called description, which uses the values stored in rank and suit to build a description of the name and value of the card. The description property uses optional binding to check whether there is a second value to display, and if so, inserts additional description detail for that second value.
Because BlackjackCard is a structure with no custom initializers, it has an implicit memberwise initializer, as described in Memberwise Initializers for Structure Types. You can use this initializer to initialize a new constant called theAceOfSpades:

let theAceOfSpades = BlackjackCard(rank: .ace, suit: .spades)
print(“theAceOfSpades: \(theAceOfSpades.description)”)
// Prints “theAceOfSpades: suit is ♠, value is 1 or 11”

Even though Rank and Suit are nested within BlackjackCard, their type can be inferred from context, and so the initialization of this instance is able to refer to the enumeration cases by their case names (.ace and .spades) alone. In the example above, the description property correctly reports that the Ace of Spades has a value of 1 or 11.

Referring to Nested Types
To use a nested type outside of its definition context, prefix its name with the name of the type it is nested within:

let heartsSymbol = BlackjackCard.Suit.hearts.rawValue
// heartsSymbol is “♡”

For the example above, this enables the names of Suit, Rank, and Values to be kept deliberately short, because their names are naturally qualified by the context in which they are defined.

Extensions

Extensions add new functionality to an existing class, structure, enumeration, or protocol type. This includes the ability to extend types for which you do not have access to the original source code (known as retroactive modeling).
Extensions in Swift can:
Add computed instance properties and computed type properties
Define instance methods and type methods
Provide new initializers
Define subscripts
Define and use new nested types
Make an existing type conform to a protocol
In Swift, you can even extend a protocol to provide implementations of its requirements or add additional functionality that conforming types can take advantage of. Extensions can add new functionality to a type, but they cannot override existing functionality.

‌Extension Syntax

Declare extensions with the extension keyword:

extension {
// new functionality to add to SomeType goes here
}
An extension can extend an existing type to make it adopt one or more protocols. To add protocol conformance, you write the protocol names the same way as you write them for a class or structure:

extension : , {
// implementation of protocol requirements goes here
}
Adding protocol conformance in this way is described in Adding Protocol Conformance with an Extension.An extension can be used to extend an existing generic type, as described in Extending a Generic Type. You can also extend a generic type to conditionally add functionality.If you define an extension to add new functionality to an existing type, the new functionality will be available on all existing instances of that type, even if they were created before the extension was defined.

‌Computed Properties

Extensions can add computed instance properties and computed type properties to existing types. This example adds five computed instance properties to Swift’s built-in Double type, to provide basic support for working with distance units:

extension {
var km: { return self * 1_000.0 }
var m: { return self }
var cm: { return self / 100.0 }
var mm: { return self / 1_000.0 }
var ft: { return self / 3.28084 }
}
let oneInch = 25.4.mm
print(“One inch is \(oneInch) meters”)
// Prints “One inch is 0.0254 meters”
let threeFeet = 3.ft
print(“Three feet is \(threeFeet) meters”)
// Prints “Three feet is 0.914399970739201 meters”

These computed properties express that a Double value should be considered as a certain unit of length. Although they are implemented as computed properties, the names of these properties can be appended to a floating-point literal value with dot syntax, as a way to use that literal value to perform distance conversions.
In this example, a Double value of 1.0 is considered to represent “one meter”. This is why the m computed property returns self—the expression 1.m is considered to calculate a Double value of 1.0.Other units require some conversion to be expressed as a value measured in meters. One kilometer is the same as 1,000 meters, so the km computed property multiplies the value by 1_000.00 to convert into a number expressed in meters. Similarly, there are 3.28084 feet in a meter, and so the ft computed property divides the underlying Double value by 3.28084, to convert it from feet to meters.
These properties are read-only computed properties, and so they are expressed without the get keyword, for brevity. Their return value is of type Double, and can be used within mathematical calculations wherever a Double is accepted:

let aMarathon = 42.km + 195.m
print(“A marathon is \(aMarathon) meters long”)
// Prints “A marathon is 42195.0 meters long”

Extensions can add new computed properties, but they cannot add stored properties, or add property observers to existing properties.

‌Initializers

Extensions can add new initializers to existing types. This enables you to extend other types to accept your own custom types as initializer parameters, or to provide additional initialization options that were not included as part of the type’s original implementation.Extensions can add new convenience initializers to a class, but they cannot add new designated initializers or deinitializers to a class. Designated initializers and deinitializers must always be provided by the original class implementation.

If you use an extension to add an initializer to a value type that provides default values for all of its stored properties and does not define any custom initializers, you can call the default initializer and memberwise initializer for that value type from within your extension’s initializer.This would not be the case if you had written the initializer as part of the value type’s original implementation, as described in Initializer Delegation for Value Types.

The example below defines a custom Rect structure to represent a geometric rectangle. The example also defines two supporting structures called Size and Point, both of which provide default values of 0.0 for all of their properties:

struct Size {
var width = 0.0, height = 0.0
}
struct Point {
var x = 0.0, y = 0.0
}
struct Rect {
var origin = Point()
var size = Size()
}

Because the Rect structure provides default values for all of its properties, it receives a default initializer and a memberwise initializer automatically, as described in Default Initializers. These initializers can be used to create new Rect instances:

let defaultRect = Rect()
let memberwiseRect = Rect(origin: Point(x: 2.0, y: 2.0),
size: Size(width: 5.0, height: 5.0))

You can extend the Rect structure to provide an additional initializer that takes a specific center point and size:

extension {
init(center: , size: ) {
let originX = center.x – (size.width / 2)
let originY = center.y – (size.height / 2)
self.init(origin: Point(x: originX, y: originY), size: size)
}
}
This new initializer starts by calculating an appropriate origin point based on the provided center point and size value. The initializer then calls the structure’s automatic memberwise initializer init(origin:size:), which stores the new origin and size values in the appropriate properties:

let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
size: Size(width: 3.0, height: 3.0))
// centerRect’s origin is (2.5, 2.5) and its size is (3.0, 3.0)

If you provide a new initializer with an extension, you are still responsible for making sure that each instance is fully initialized once the initializer completes.

Methods

Extensions can add new instance methods and type methods to existing types. The following example adds a new instance method called repetitions to the Int type:

extension {
func repetitions(task: () -> ) {

for _ in 0.. Void, which indicates a function that has no parameters and does not return a value.
After defining this extension, you can call the repetitions(task:) method on any integer to perform a task that many number of times:

3.repetitions {
print(“Hello!”)
}
// Hello!
// Hello!
// Hello!

Mutating Instance Methods

Instance methods added with an extension can also modify (or mutate) the instance itself. Structure and enumeration methods that modify self or its properties must mark the instance method as mutating, just like mutating methods from an original implementation.
The example below adds a new mutating method called square to Swift’s Int type, which squares the original value:

extension {
mutating func square() {
self = self * self
}
}
var someInt = 3
someInt.square()
// someInt is now 9


Subscripts

Extensions can add new subscripts to an existing type. This example adds an integer subscript to Swift’s built-in Int type. This subscript [n] returns the decimal digit n places in from the right of the number:
123456789[0] returns 9
123456789[1] returns 8
…and so on:

extension {
subscript(digitIndex: ) -> {
var decimalBase = 1
for _ in 0.. 0:
return .positive
default:
return .negative
}
}
}

This example adds a new nested enumeration to Int. This enumeration, called Kind, expresses the kind of number that a particular integer represents. Specifically, it expresses whether the number is negative, zero, or positive.This example also adds a new computed instance property to Int, called kind, which returns the appropriate Kind enumeration case for that integer.
The nested enumeration can now be used with any Int value:

func printIntegerKinds(_ numbers: []) {
for number in numbers {
switch number.kind {
case .negative:
print(“- “, terminator: “”)
case .zero:
print(“0 “, terminator: “”)
case .positive:
print(“+ “, terminator: “”)
}
}
print(“”)
}
printIntegerKinds([3, 19, -27, 0, -6, 0, 7])
// Prints “+ + – 0 – 0 + “

This function, printIntegerKinds(_:), takes an input array of Int values and iterates over those values in turn. For each integer in the array, the function considers the kind computed property for that integer, and prints an appropriate description.number.kind is already known to be of type Int.Kind. Because of this, all of the Int.Kind case values can be written in shorthand form inside the switch statement, such as .negative rather than Int.Kind.negative.

This Is A Custom Widget

This Sliding Bar can be switched on or off in theme options, and can take any widget you throw at it or even fill it with your custom HTML Code. Its perfect for grabbing the attention of your viewers. Choose between 1, 2, 3 or 4 columns, set the background color, widget divider color, activate transparency, a top border or fully disable it on desktop and mobile.

This Is A Custom Widget

This Sliding Bar can be switched on or off in theme options, and can take any widget you throw at it or even fill it with your custom HTML Code. Its perfect for grabbing the attention of your viewers. Choose between 1, 2, 3 or 4 columns, set the background color, widget divider color, activate transparency, a top border or fully disable it on desktop and mobile.