© Radoslava Leseva Adams and Hristo Lesev 2016

Radoslava Leseva Adams and Hristo Lesev, Migrating to Swift from Flash and ActionScript, 10.1007/978-1-4842-1666-8_17

17. Swift Language Basics

Radoslava Leseva Adams and Hristo Lesev2

(1)London, UK

(2)Kazanlak, Bulgaria

The first impression Flash developers usually share with us about Swift is “Oh, it’s almost ActionScript, isn’t it!” What they refer to is how readable syntax-wise a piece of Swift code is, compared to Objective-C, which used to be the typical choice when switching to native iOS programming. And they have a point: in contrast to transitioning to Objective-C, moving to Swift from ActionScript has a much lower entry point. Swift offers a lot more than that and in this chapter we will start unpacking its bag of goodies.

We will start with why you might want to move on to Swift in the first place and how your ActionScript experience can soften the learning curve. Then we will set up a playground, where you can quickly run code snippets, and will cover a few basic points, which you will need before moving on to the next chapters. You will see how to declare variables, constants, and functions and how to control access to your code, and you will become familiar with basic error handling.

What Swift encourages You to Do

You will discover that a lot of concepts you have been using in ActionScript are not only present in Swift but with added power. This adds richness and expressiveness to the language.

What I personally most like about Swift, however, is the fact that it encourages good programming habits. Or enforces them, as may be the case. It gives you the option and the incentive to be concise with your code, but at the same time it forces you to state your intentions clearly. Swift’s compiler is complicit in this: it will guide your hand and occasionally slap it, making it hard for you to write bad code unintentionally.

Be Concise

The first thing I noticed about Swift was the lack of semicolons. I must admit that at that point I wrinkled my nose at it and thought “But, but, but . . . Why?!”

The thing is, Swift doesn’t stop you from using semicolons. But it doesn’t require you to use them either, unless you put separate statements on the same line. This underpins part of Swift’s philosophy: you can write code as verbose as you need it, but you also have the option to be as concise as humanly possible.

I say “humanly possible,” because the trouble with conciseness is not a compiler’s problem: if a shortcut is legal, the compiler will understand it. However, both writing code that is too verbose and writing code that is too brief can interfere with human readability, so exercise your judgment.

Here is an example: the two pieces of code in Listing 17-1 and Listing 17-2 are both valid Swift and both do exactly the same: they define an array of integers and obtain a sorted copy of it.

Listing 17-1. Sorting an Integer Array: Verbose
let arrayOfInts: Array<Int> = [6, 3, 4];
let sortedArray: Array<Int> = arrayOfInts.sort(
    { (item1: Int, item2: Int) -> Bool in return item1 < item2 } );
Listing 17-2. Sorting an Integer Array: Concise
let arrayOfInts = [6, 3, 4]
let sortedArray = arrayOfInts.sort(<)

The rest of the chapters in Part IV will explain what is going on with the code in Listings 17-1 and 17-2. For the missing type declarations in Listing 17-2 see the section “Type safety and Type Inference” in Chapter 19 . For the syntax in the function within the brackets in the first example and how it got reduced to a single operator in the second example see the section “Closures” in Chapter 22 . To find out what the let keyword means see the section “Declaring Variables and Constants,” later in this chapter. As for the missing semicolons . . . get over it. That’s how it is in Swift.

Be Explicit

One of the dangers of getting carried away with conciseness is ambiguity: you may end up writing code that is syntactically valid but doesn’t actually do what you meant it to do. For example, in most other languages it is too easy to swap two arguments of the same type by mistake: the code will compile, it will look convincing to the human eye and the mistake will only come to bite you as a bug later on, maybe even after you have shipped the code. (To see how Swift can help with this issue, see the section “Defining and Calling Functions” later in this chapter.)

To say that Swift encourages you to be explicit would be an understatement. It’s more like your grandmother who lovingly, but with some force, nudged you to say “please” and “thank you” to her neighbors. The Swift compiler nudges you in a similar way to state your intentions with every line of code you write.

For example, the ActionScript equivalent of the code in Listing 17-3 would result in all three print calls being executed, because I didn’t put a break statement after each case. In Swift this is not the default behavior: to get execution to continue to the next case statement whether there is a break or not, even if a match has been found, I would need to use the fallthrough keyword.

In fact, the code in Listing 17-3 will not compile. While in other languages you may not even get a warning if you omit the default clause in a switch statement , in Swift this causes a compilation error. For details on what else switch statements can do for you (there is a lot!) see Chapter 20 .

Listing 17-3. Spot the Missing Statement. Hint: It Is Not a break
let direction = 3

switch direction {
    case 1: print("Go South")
    case 2: print("Go North")
    case 3: print("Go East")
}

The effect of having to be explicit is twofold:

  • You are less likely to suffer from bugs caused by accident and which, unfortunately, make for lexically valid code. For example, in Swift you can’t unintentionally put the assignment operator (=) where you meant to use the equality operator (==) (more on this in Chapter 18 ).

  • By writing code that explicitly states what you mean, you end up with self-documented code and less need for comments that are (a) never read and (b) by definition out of date with the code they explain.

Take Advantage of the Compiler

In his invaluable work,1 Steve Maguire talks about a hypothetical compiler, which would catch bugs for you. His book helps C developers get as close possible to this dream by teaching techniques that help the compiler help you (among other things) by adopting certain coding habits—for example, putting the (more) constant value on the left of the equals operator (==), so that the compiler can shout at you if you accidentally used the assignment operator (=).

Although a lot of bugs you will encounter are not possible to catch at compile time, Swift’s compiler comes close to Steve Maguire’s dream2 and makes it almost impossible to default to bad habits.

A lot of what would be compiler warnings show up as errors in Swift. As likely as this is to irritate you initially,3 you will probably be grateful in the long run, as you will have adopted good coding habits and the maintenance of your apps costs you a lot less for lack of easily preventable bugs.

Coming from ActionScript: Advantages and Surprises

Having experience with ActionScript, you will find yourself at an advantage when you transition to native development with Swift. This section provides a brief overview of the main areas where your prior knowledge will come in handy: syntax, programming concepts, and memory management. I have also included a few differences in Swift, which you may want to be aware of.

Syntax

If you grew up speaking Objective-C, you were probably used to its bulky syntax and it didn’t bother you very much. Transitioning to it from a language like ActionScript, however, was initially an exercise in learning how to read. In contrast, Swift does read a lot like ActionScript in how you define or access things.

With that said, Swift is not ActionScript and there are a couple of things that might seem obscure at first:

  • The Optional type: you have likely noticed a lot of exclamation and question marks in Swift tutorials and in the examples in the other parts of this book. Chapter 19 demystifies their use and shows you how optionals can make your life easier.

  • Conciseness, whose praises we sang earlier, can be a double-edged sword. It is a wonderful thing to be able to keep your statements short and clutter-free, but for a newcomer the second line, shown in Listing 17-2, may seem like a syntax error at first. Practice will help you with this: as Swift doesn’t force you to be brief, you can initially opt for the long syntax and gradually transition to omitting bits of code that the compiler can infer and that you can too.

Programming Concepts

Swift uses most of the programming concepts with which you are already familiar, including the object-oriented programming paradigm. A big part of your transition from ActionScript will be in the spirit of “Right. How do I bend a spoon in Swift?,” rather than having to first bend your mind around the thought that “There is no spoon,”4 as you might do if you were migrating to, say, a functional language.

If Swift were exactly the same as ActionScript, though, it would probably have been called ActionScript and not Swift, so be prepared for corners where we will need to shed light. Some of these are explained in context:

  • Operator overloading in Chapter 18

  • Optionals and tuples in Chapter 19

  • Using labels in Chapter 20

  • Deinitialization for classes in Chapter 21

  • Structures in Chapter 21

To a few ideas, which might need a deeper looking into, we have dedicated a separate chapter (Chapter 22 ).

Memory Management

ActionScript uses both garbage collection (GC) and automatic reference counting (ARC) to manage memory, though the latter is not spoken of very much. A garbage collector may do a good job of finding cyclic references and freeing up memory that otherwise may have leaked, but you are not in control of when it kicks in and this can hurt performance. Over time, ActionScript developers have come up with hacks and workarounds to get some control over when GC is performed.

Swift classes use ARC , so you should be on familiar ground there. Moreover, as this is not a garbage-collected language, you will have control over when instances are deallocated. And, unlike moving to Objective-C, you will not have to get your head around pointers.

Swift also helps you be more mindful about how you use memory, as it distinguishes between reference types and value types (more on that in Chapter 21).

How to Use the Code Examples: Playgrounds

This part of the book presents the Swift language with the help of a lot of little snippets of code. To try them out, you don’t need to set up and deploy a big project. Instead, you can take advantage of another goodie that the Xcode has: Playgrounds.

A playground allows you to experiment with code and even create prototypes very quickly. Instead of having to build and install your code on a device or on one of the iOS simulators, you can see it being evaluated and run as you type. Ah, I am so excited about what you can do in a playground: animations, interactive UI, sleek-looking documentation in line with your code. Too bad that for our purposes we will only need the more mundane features: typing code and seeing it run will do.

Apart from being able to run examples unburdened by a big project, using a playground also means that you can dip in and out of the following chapters when you need to understand a specific bit of the language while doing the tutorials in the rest of the book.

Let us set up your first playground. You can use the same playground for all of the examples in this part of the book or you can create a new one as you start each chapter. When you accumulate a lot of lines of code in the same playground you may find Xcode getting slower, as it runs and evaluates all of the code on each keystroke, so you might find keeping separate playgrounds more practical.

From Xcode’s main menu select FileNewPlayground, give your playground a name (I named mine Swift Test Playground) and let the wizard create it for you. Upon first opening you will see an Editor displaying the code in Listing 17-4.

Listing 17-4. Code in a Fresh Playground
//: Playground - noun: a place where people can play

import UIKit

var str = "Hello, playground"

To dip your toe in, add a call to print out the value of str and let us have a brief exploration of the workspace (Listing 17-5).

Listing 17-5. Add a Line to the Playground Code
print(str)

The playground looks a lot like what you are used to when creating iOS projects, only trimmed down (Figure 17-1). You have the Editor in the middle: here it has an inspection area on the right, where you can see your expressions evaluated at runtime. There is also a Debug area, where you can output information with print. This is also where you can see compilation and runtime error messages. On the left is the familiar Navigation area, which you can toggle to see the structure of your playground (you can add source and resource files to it), inspect symbols, do textual searches, or explore issues found by the compiler.

A371202_1_En_17_Fig1_HTML.jpg
Figure 17-1. Set up a playground in Xcode

With your first playground set up, let our journey through Swift begin. We will start with a few basic things before we go deeper in the next chapters.

First Things About Swift

The rest of this chapter will lay some groundwork and housekeeping rules. You can use the playground we set up in the previous section to try out some of the snippets of code.

Declaring Variables and Constants

The first thing you are likely to ask when faced with the blank page, all right, screen, is: how do I declare a variable? Use the var keyword to declare a variable and the let keyword to declare a constant (Listing 17-6).

Listing 17-6. Declaring Variables and Constants
var anIntegerVariable = 10
let aStringConstant = "I am a string. And I am constant."

A nice thing about the Swift compiler is that it encourages you to use constants instead of variables wherever possible: if you declare a variable, but never change its value, you will get a warning like the one in Figure 17-2 suggesting that you change it to a constant by replacing var with let.

A371202_1_En_17_Fig2_HTML.jpg
Figure 17-2. The compiler encourages the use of let wherever possible

Listing 17-6 shows you how to declare variables and constants in the spirit of conciseness: you can see that I have omitted the type declarations of anIntegerVariable and aStringContant. You can include them as you do in ActionScript, following a colon after the name of the variable, as in Listing 17-7.

Listing 17-7. Explicitly adding type declarations
var anIntegerVariable: Int = 10
let aStringConstant: String = "I am a string. And I am constant."

In the spirit of explicitness, however, Swift will not let you use the line in Listing 17-8, which is possible in ActionScript.

Listing 17-8. This Line Will Compile in ActionScript, But Not in Swift
var aVariable;

The Swift compiler is clever, but it will not tolerate not knowing the type of aVariable. For it to work it out you need to either state it explicitly or assign a value, from which the type can be inferred.

Making Comments

You add comments in Swift the same way you do in ActionScript. Use two forward slashes to prefix single-line comments:

// This is a single-line comment.

Put multiline comments inside the familiar forward-slash-plus-asterisk and asterisk-plus-forward-slash combination:

/* This is a comment,
which spans multiple lines. */

Printing in the Console

In Swift you can print diagnostic information in Xcode’s console with the print function, much like you do with trace in ActionScript. You can use print with any expression: to print it out as part of a string literal, put the expression in parentheses inside the string quotes and prefix it with a backslash () as shown in Listing 17-9:

Listing 17-9. Printing Out a Value in the Console
print(anIntegerVariable)
// output: 10


print("The value of anIntegerVariable is (anIntegerVariable).")
// output: The value of anIntegerVariable is 10.

For more details on inserting values in string literals and using escape sequences see the section “Strings” in Chapter 19 .

Defining and Calling Functions

To define a function, use the func keyword, followed by the name of the function, followed by a comma-separated argument list in parentheses and, if the function returns a result, add a return arrow (->), followed by the type of the result (Listing 17-10). If your function does not return a result, you don’t need to add anything after the closing parenthesis of the argument list. For functions that don’t take arguments you still need the parentheses after the function name, though their argument list will be empty.

Listing 17-10. Defining Functions in Swift
func divide(a: Double, b: Double) -> Double {
    return a / b
}


func printAQuote(quote: String, byAuthor: String) {
    print("'(quote)' (byAuthor)")
}

Naming Arguments

The code in Listing 17-10 could almost be ActionScript, couldn’t it? You will notice a difference when making a call to a function, however. The difference is not big, but it is important: in Swift function arguments have what is known as local and external names. A local name is the name that will be used to refer to the argument inside the function body and an external name is what the caller of a function will use to label the argument. There are a few rules about local and external names:

  • To provide external names for your arguments explicitly, put them before the internal names (Listing 17-11).

Listing 17-11. Providing External Argument Names
// Add explicit external argument names
func divide(dividend a: Double, divisor b: Double) -> Double {
    return a / b
}


// Label your arguments with their external names when making a call:
divide(dividend: 1, divisor: 0)

Now a and b are the names, which the divide function can use locally, but when you call divide you need to label its arguments dividend and divisor, respectively.

Remember what we said earlier about accidentally swapping arguments of the same type? The external argument names (which are actually an Objective-C legacy) help avoid that: they will not make the compiler complain if you swapped 1 and 0 in the example above,5 but having to label your arguments makes it harder for you to swap them without noticing.

  • Local and external names can be the same. If you don’t explicitly provide an external name for one of your parameters, its name will serve both as a local and as an external name. The first argument in the list is an exception, which will be explained in the next rule.

For example, calling the second function we defined in Listing 17-10 would look like this (Listing 17-12):

Listing 17-12. Calling a Function with External Argument Name
printAQuote("Life is too short to remove USB safely.",
             fromAuthor: "Anonymous")

Notice how the second argument has a label, although we did not explicitly set an external name for it in the function definition.

All arguments of a function, but the first one, get both a local and an external name by default. If you want the first argument to be referred to by an external name too, you need to provide it explicitly. Apple encourages a naming convention, in which the external name of the first argument is implied by the name of the function. For example in printAQuote you would expect to provide a quote as an argument.

There is an exception to this rule too: if the function is an initializer method, all of its arguments get external names by default (see Chapter 21 on initializers).

Note

Swift 3 introduces a change, in order to establish consistent label behavior across all parameters, including first labels. This means that the first argument too will get a default external name if you do not provide one explicitly. When you call the printAQuote function, you will need to provide both labels: printAQuote(quote: "...", fromAuthor: "...").

  • You can opt out of external names for your arguments. Once again, you need to state this explicitly by putting an underscore where the external name would be (Listing 17-13):

    Listing 17-13. Ignoring External Argument Names
    // Put an underscore in place of the external name:
    func printAQuote(quote: String, _ fromAuthor: String) {
        print("'(quote)' (fromAuthor)")
    }


    // Now you don't have to label the arguments when making a call:
    printAQuote("Programs must be written for people to read,
                 and only incidentally for machines to execute.",  "Hal Abelson")

Function Parameters

Let us have a look at how function parameters are treated in Swift and what your options are.

Parameters Are Constant by Default

By default all parameters of a function are constants and you can’t make changes to them inside the body of the function.

In-Out and Variable Parameters

You can opt for non-constant behavior by prepending a parameter name with the inout keyword. An in-out parameter is passed by reference. In other words, a function that takes an in-out parameter will access the original variable that you passed in, rather than a copy of it and any changes you make to that variable inside the function will persist after the function returns. Listing 17-14 shows an example of a function, which takes a string and modifies it. Note that at the point of calling the function we need to prepend the in-out parameter with an ampersand (&).

Listing 17-14. Using In-Out Parameters
func modifyMyString(inout str: String) {
    str = "Ha! I can override you!"
    print(str)
}


var myStr = "I am the boss."
modifyMyString(&myStr)
// Output: "Ha! I can override you!"


print(myStr)
// Output: "Ha! I can override you!"
Note

Swift 3 comes with a different syntax for using the inout keyword: it needs to be on the right side of the colon: func modifyMyString(str: inout String).

If you do not need a modified parameter value to persist after the return of the function you passed it in, you can use the var keyword. Note that making changes a var argument will create a copy of it, which serves as a local variable inside the function (Listing 17-15).

Listing 17-15. Using Variable Parameters
func modifyMyString(var str: String) {
    str = "Ha! I can override you!"
    print(str)
}


var myStr = "I am the boss."
modifyMyString(myStr)
// Output: “Ha! I can override you!”


print(myStr)
// Output: "I am the boss."
Note

In Swift 3 the var keyword is deprecated. Instead of using a var parameter you can declare a local variable and assign the value of the parameter to it. This achieves the exact same behavior but makes it a lot more obvious: a copy of the value is made, which you can modify, but you cannot access the modified value once the function returns.

Variadic Parameters

A function can be defined to take parameters that vary in number by using a variadic parameter. This parameter takes one or more values of the same type and is defined by adding three dots at the end of its declaration. Inside the function you can iterate through the values of the parameter and query their number by calling parameterName.count. Something to keep in mind is that you can define only one variadic parameter per function.

The example in Listing 17-16 uses a variadic parameter, called numbers, to find the maximum in a list of integer numbers:

Listing 17-16. Iterating Through a Variadic Parameter
func findMaximum(numbers: Int...) -> Int {
    var maxNum = Int.min
    for number in numbers {
        if number > maxNum {
            maxNum = number
        }
    }


    return maxNum
}


findMaximum(300, 4, 99) // returns 300
Providing Default Values

As in ActionScript, you can provide default values for function arguments. You can do this for constant and for variable parameters but not for in-out parameters.

Listing 17-17 shows the printAQuote function, which we used earlier, this time defined to set the byAuthor parameter to "Anonymous" by default. Note that now the call to the function does not have to include a second parameter.

Listing 17-17. Providing Default Parameter Values
func printAQuote(quote: String, byAuthor: String = "Anonymous") {
    print("'(quote)' (byAuthor)")
}


// You can skip the byAuthor argument, as it has a default value:
printAQuote("Sm;)e")

Function Overloading

Here is something that ActionScript does not let you do. You can define several functions with the same name and the same scope: as long as they have a different number or different types of parameters, the compiler will make sure that the correct one is selected when you make a call.

The example in Listing 17-18 illustrates that: we have defined three functions called printInfo, all of which print out their parameters into the console.

Listing 17-18. Overloading Functions
func printInfo(i: Int) {
    print("Here is an integer: (i)")
}


func printInfo(s: String) {
    print("Here is a string: '(s)'")
}


func printInfo(i: Int, s: String) {
    print("Here is an integer: (i) and a string: '(s)'")
}


printInfo(3) // Calls the first function
printInfo("Ta-da!") // Calls the second function
printInfo(40, s: "Ali Baba's thieves") // Calls the third function

You can also overload methods (see Chapter 21 ) and subscripts (see Chapter 22 ).

Access Control Rules

You have already seen from the tutorials in this book how you can structure your projects and that Swift code goes into .swift files. These files and the modules they form are the basis of defining how code is accessed. Here module is meant as a bunch of files you build and ship together as an application or as a framework.

There are three levels of access, which determine the visibility of a piece of code:

  • private entities are only visible to code in the same file where they were defined.

  • internal bits of code are accessible from source files inside the same module.

  • public entities are accessible everywhere within the same module, as well as to code that uses it. They define the interface to the module.

In the previous definitions I use entities as a substitute for “almost anything you can define”: global variables, constants, and functions; classes, structures, and enumerations, as well as their members; and also protocols. The access modifiers can be applied to all these. The members of a protocol are an exception: you can define a private protocol but you cannot define its members as private.

The default access level is internal and is applied if you don’t explicitly provide an access modifier when you declare an entity.

If you are wondering “How about protected?,” the answer is that it doesn’t exist in Swift. To find out why see Chapter 21 . This is also where we you can find information on structures and protocols, which were mentioned previously. For enumerations, see Chapter 22 .

Handling Errors

To handle error conditions in ActionScript we have the Error class at our disposal. We can return Error instances as function results or throw them in cases, which requires interrupting the flow of execution, when it doesn’t make sense to continue an operation if a certain error condition arises, for example. We can also subclass Error, in order to customize it and add information.

The situation in Swift is similar, but with some subtle differences. Instead of an error base class, there is a protocol, called ErrorType. To use an error type, you need to define it yourself and have it conform to the ErrorType protocol: using an enumeration for that is usually quite a good idea. You can read more on protocols and conforming to them in Chapter 21 and on enumerations—in Chapter 22 .

If you write a function that throws an error, you need to put the throws keyword in its definition: it goes after the argument list and before the return type of the function: func iMayThrowAnError() throws -> String.

To catch an error that may be thrown by a function you call, use a do-try-catch statement .

In some cases you will want a certain piece of code to be executed at the end of a function (to clean up resources, for example) irrespective of whether the function’s execution was interrupted by a thrown error. Such code you can put inside a defer statement: this is similar to using finally in ActionScript.

Table 17-1 provides a comparison between the skeleton of a try-catch-finally statement in ActionScript and a do-try-catch statement with a defer clause in Swift.

Table 17-1. Comparison Between Try-Catch Statements in ActionScript and in Swift

ActionScript

Swift

try {

statements;

} catch (e:Error) {

statements;

} finally {

statements;

}

do {

try expression

statement

} catch ErrorType {

statements

}

defer {

statements

}

A quick note on defer: you are not limited to using it only in situations in which you need to handle errors. For example, you can put a block of code inside defer to ensure that it is always executed in a function with multiple returns (and save on code repetition before every return statement). You can also use it inside loops or do statements. Note that when you have multiple defer statements within the same scope, they get executed in reverse order of how they appear in the code.

Let us see all of this in action with an example. Say we are creating an app that allows users to watch TV online and choose a TV channel by typing its name. We will define a couple of functions: channelNameEntered will take a channel name as an argument and will be called when the user types it in. A second function, switchToChannel, will be called by channelNameEntered to do the actual work for finding and switching to the selected channel. switchToChannel will alert its caller about possible error conditions that make it impossible to activate the given channel: the channel doesn’t exist, it’s under parental control, or subscription to it has expired.

The enumeration in Listing 17-19 will represent the error conditions. For the moment you can think of an enumeration as a way of keeping a set of names together: in this case it will help us define a set of names for the different errors we may encounter. (See Chapter 22 for an in-depth introduction to enumerations.)

Listing 17-19. Defining an Error Type
enum ChannelChangeError: ErrorType {
    case InvalidChannelName
    case ParentalControlOn
    case SubscriptionExpired
}

The function that changes the channels checks if there is any reason not to proceed with the change and if it finds one, it throws one of the error names defined in ChanelChangeError. Note that throw takes the code execution out of the function, much like a return 6— (see the example in Listing 17-20).

Listing 17-20. Throwing an Error
func switchToChannel(name: String) throws {
    if !channelExists(name) {
        throw ChannelChangeError.InvalidChannelName
    }


    if isParentalControlOn(name) {
        throw ChannelChangeError.ParentalControlOn
    }


    if !inSubscriptionList(name) {
        throw ChannelChangeError.SubscriptionExpired
    }


    // Proceed to change the channel
}

Finally, the function that calls switchToChannel needs to handle the different types of errors that may be thrown at it. For that purpose we put the call to switchToChannel inside a do-try statement as shown on Listing 17-21, followed by two catch statements to catch two of the error conditions: ChannelChangeError.InvalidChannelName and ChannelChangeError.ParentalControlOn. The third catch statement is a blanket one: it will catch any other error that is thrown and was not caught by the catch statements above it. Note how one of the catch statements rethrows the error, instead of handling it: this way the error is propagated up the call stack to be handled by the caller of channelNameEntered.

The code in the defer statement will be called before the execution of channelNameEntered finishes. This code will run whether an error was caught inside the function or not.

Listing 17-21. Catching, Handling, and Rethrowing Errors
func channelNameEntered(name: String) throws {
    do {
        try switchToChannel("Cartoons 24/7")
    } catch ChannelChangeError.InvalidChannelName {
        // Rethrow the error to be handled
        // by the caller of channelNameEntered:
        throw ChannelChangeError.InvalidChannelName
    } catch ChannelChangeError.ParentalControlOn {
        // Handle the error here and don't propagate it up:
        // Update the screen to show a cheeky picture of a parent.
    } catch {
        // This is a blanket error handler for any errors
        // that were not caught by the previous catch statements.
    }
    defer {
        // The code after the defer statement
        // will be executed before the execution leaves this function,
        // no matter whether any error was thrown.


        // Save the chanel name in the browsing history,
        // even if switching to it was not possible.
        // ... possibly to alert parents.
    }
}

You can find even more subtle ways of using and catching errors in Apple’s online book The Swift Programming Language.

Summary

This chapter paved the way to learning Swift by covering a few essential points: how to declare variables, constants, and functions; how to print out diagnostic information; and the basics of error handling. You are set up with a playground, where you can quickly test code snippets and explore Swift’s features.

I hope it also made you excited about learning a new language, which, among other things is designed in a way to encourage good programming habits. The main thing to keep in mind about Swift, however, is that it will not stop you from shooting yourself in the foot: you have all the means and tools to do it. But you really need to mean to shoot yourself in the foot. And explicitly tell the Swift compiler that you do mean it.7

With this disclaimer out of the way we can move on to having a closer look at Swift. The next chapter introduces Swift’s operators and what surprises they may have for an ActionScript developer.

Footnotes

1 Steve Maguire, Writing Solid Code (Microsoft Press, 1993).

2 Or this is my take on it. Mr. Maguire might, in fact, be running away in disgust.

3 Try to leave an uninitialized class member, for example . . . . More on that in Chapter 21 .

4 In case you were too young to see The Matrix movie when it first came out, type “there is no spoon” in YouTube—the scene is worth a thousand words.

5 If you call this function with the divisor set to zero, you will see another Swift feature demonstrated. Instead of throwing a “division by zero” error, it returns infinity (inf).

6 Apple’s manual says that a throw in Swift is like a return when it comes to performance too, as no stack unwinding is done when an error is thrown, in contrast to what typically happens in other languages.

7 Or, as my husband put it: using Swift is like taking legal advice from a lawyer. He can make it hard for you to do the wrong thing, but he will not stop you from doing it. And in the end, the one person you cannot blame if things go wrong is the lawyer.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset