Learning Swift

Apple released Swift officially as an alternative language for development, apart from Objective-C. It looks and reads like an easy-to-use scripting-like language. It is a modern language, and has the features of most modern languages such as Python, Ruby, Lua and Scala. Swift removes the need for semicolons and uses the standard double slash for comments, amongst other things, as shown here:

//This is a comment

Console output printing

The println function is used for printing data. Swift also has a more evolved println function that allows for formatted printing. The value of a variable can be inserted into a string by enclosing the variable name in brackets preceded by a slash: (varname). This format has to be enclosed in double quotes to make it work.

println("Hello World")
println("This is fine too");

var ver = 6
println("Hello from Xcode (ver)")

Working with variables

We can add two numbers, say 1 and 3, but if our program just added 1 and 3, we would not have much use of the same. If we wanted to write a program that adds two numbers that we pass and it returns a result, then it would be of some use. There are a couple of things that need attention here; we need to first store the numbers in some space and then be able to access them. Variables are basically storage spaces in the system that hold a value of a particular type, and access is via named labels. It would be easier to remember a variable called age than one called 0xff22400d3. Swift has two types of variables; mutable and immutable. Immutable variables are called constants. The values that they hold cannot be changed.

When dealing with large numbers, it is difficult to type them in or read them while trying to group them mentally. A number like 123456789 is not as easy to decipher as 123,456,789 is. While assigning the same number to variables, it is not easy to read and check the same, as you cannot set something like var largeNum = 1,234,567.89. However, Swift allows you to format your numbers with an underscore as 1_234.50, or in the preceding example as 1_234_567.89:

var thousands = 4_693.45
var billions = 3_142_857_143
var crazyNumber = 1_23_456_7_890

Variable types

In Swift, a variable can be of any type as available. However, there are some internal types that are provided by the system, they are as follows:

  • Int, Float, Double
  • String
  • Array, Dictionary
  • Bool

Declaring variables

All variables in Swift need to be declared prior to using them, as Swift is a typesafe language. The compiler checks for the types and highlights of potential issues with the use of non-matching variable types used. So, a variable that is declared as Int cannot hold any other type than Int. The two keywords used to declare variables are let and var; let declares constants (the value for these variables can be set once and not changed after that) and var declares mutable variables:

var publisher:String
let name:String = "Learning Xcode 6"
var year:Int = 2014

Variables can either just be declared or can be both, declared and assigned a value. Once declared, a mutable variable can be reassigned a new value; whereas, if we try to do so with a constant, the compiler would complain:

name = "Learning Visual Studio"    // Compiler complains
year = 2015                        // Works ok

The Swift compiler is quite intelligent and it can implicitly define variables. It knows that when you type the following:

let author = "Jayant Varma"

The variable author is of type String as the value assigned to it is of type String and it does not have to be explicitly declared.

Multiple variables can be declared on the same line too by separating them with commas.

var a = 1, b = 2.3, c = "Four"
var x, y, x : Double

Tip

If you have to declare a variable that is a keyword, you can enclose it in back ticks `. You can access all the variables using back ticks, though it's not very convenient.

What are Int, Double, and Float variables

Implicit assignment works even with numbers, and all the numbers without the decimal point are considered of type Int and all with a decimal point are of type Double:

var nextYear = year + 1        // autocasts to type Int

In cases where you wanted this variable to be Double and not Int, you could explicitly assign it to type Double as follows:

var nextYearAndHalf = Double(year) + 1.5

When working with iOS SDK, you will realize that you will need another type of variable for numbers, called CGFloat; while it is a floating point number, it is a different structure than Double of Float or Int.

Adding different types

As mentioned earlier, the Swift compiler expects the types to be of the expected types, so while a number is a number and broadly we consider 1, 1.0, and "1.0" as the same, for computers, and more so for Swift, these are three different types, namely Int, Double, and String. When working with different types, we need to convert them to the same type in order for it to work:

var pi = 3.14            // autocast to Double
var e = 3                // autocast to Int
var pie = pi + e         // Compiler error - not similar types

To resolve such issues, we need to cast the values to the expected type (if they can be converted), we can fix this by using the following line of code:

var pie = pi + Double(e)    // works as expected

Or, as we discussed in the previous example, regarding CGFloats, you could use the following line of code:

var cgPie = CGFloat(pie)    // this is now of CGFloat type

The same is true for strings; we can easily do something like the following:

var hello = "Hello"
var world = "World"
var test = hello + world

However, we get an error when we try something like this:

var appname = "Xcode"
var appversion = 6
var bookname = appname + appversion         // we get an error

This is because we are trying to add type String with type Int. We can convert Int to String and it would work fine, we can do that easily by using the following line of code:

var bookname = appname + String(appversion)

Or, use the string formatting feature in Swift:

var sBookname = "(appname) (appversion)"

Booleans

Booleans are simple true and false values, and the variable type in Swift is called Bool. They form the basis for a lot of logic and conditions. It can be used either by setting them explicitly via declaration, or can be set via conditions and never assigned to variables, as shown here:

var worksOnWindows = false
if appversion > 6 {
    println("Cutting edge version")
 if worksOnWindows == true {
  println("and it works on Windows too")
 }
}

In the first line, we explicitly set the value of a variable to type Bool, and in the second line, we use the result of the condition appversion > 6, which evaluates to either true or false.

Arrays and dictionaries

Sometimes, we need multiple variables, say a student enrolled at university, and we want to store the name of the classes they are enrolled in. We can have something like this:

var class1 = "Math"
var class2 = "Creative English"
var class3 = "Compiler Theory"

This works but is not practical as the more classes the student is enrolled in, the more variables there will be. The student might enroll in a few classes this semester and might take additional classes in the next semester. How would we know how many classes the student was enrolled in? How would we access the variable names in our code? If we were to use the classXX format by name, we are hardcoding our logic and this would not be good. For this purpose we use an Array.

Array objects

An array stores a list of values and these can be accessed via a sequential index. In simple terms, we can access the list using a numeric index that is in sequence, starting from 0 up to the number of values held in the array. Arrays are declared in Swift as follows:

var arrClasses:[String]    //shorthand declaration

The alternative way is to declare an array as follows:

var arrClasses = Array<String>()  //declaration

This tells the compiler that arrClasses is a type Array variable that holds String values. With arrays, we also get additional functions that allow us to work with the array, such as, to get the number of elements in the array we can use the count function.

Initializing array objects

Arrays need to be initialized, we can either initialize them with a blank list, or we can populate the values while initializing them, as shown in the following code:

var arrClasses:[String]  

This only declares the variable called arrClasses to be of type array of string, but it is not initialized and cannot be used prior to initialization:

arrClasses = []            //Initialized as blank

A blank array can be declared and initialized by using var arrBlank = [Int](). It can also be initialized with a set of default repeating values like this:

var arrZeros = [Int](count:10, repeatedValue:0)
// Array of Ints with 10 items and all initialized to 0

Arrays can also be initialized with default values, as follows:

var arrSlots = ["Morning", "Afternoon", "Evening", "Night"]

This would have created an array with four string elements. If we will not have the need to modify this array, we can declare it with let instead.

In our example, we can now have the student enroll in several classes and we can know the classes the student is enrolled in and also the number by accessing the array:

var numberOfClasses = arrClasses.count

Apart from the count property, there is another property called isEmpty that returns true if there are no elements in the array.

Appending values

More elements can be added to the array using the append method, as shown in the following code:

arrClasses.append("Finance")
arrClasses.append("Learning MS Office")

Or, we can also use the += operator as follows:

arrClasses += ["Algorithms"]
arrClasses += ["Basket Weaving", "Bread Making", "Cheese Tasting"]
numberOfClasses = arrClasses.count

The index can be used to access the elements or to modify the elements, as follows:

arrClasses[0] = "Basics of Finance"  // Modifies the 1st element
Removing values

Elements can be removed using the remove method. The remove function returns the element value it is removing:

arrClasses.removeAtIndex(1)          // Removes the 2nd element

We can also remove the last element or remove all the elements using the removeLast or removeAll functions.

Inserting values

We can also add an item specifically at an index position using the insert function:

arrClasses.insert("Creative Writing", atIndex: 2)
Iterating values

We can iterate through the array using a for loop:

for sClass in arrClasses {
 println("class name : (sClass)")
}
Enumerating values

Another way is to enumerate the items in an array using the enumerate function:

for (index, value) in enumerate(arrClass){
  println("Class at index (index+1) is (value)")
}

Note

We used index+1 in the code because all the array indexes are 0 based.

Dictionary objects

Dictionaries are also called key-value pairs or associative index. This is because, instead of a numeric index value, we have an associative value to access the element or a key to retrieve the value. This is quite useful in cases where you might want to access an item (the value) by a key (usually a string) instead of using a numerical index. Declaring dictionaries is similar to declaring arrays. However, the only difference is that Swift expects that the variable types for both the key and the value be specified:

var dClassTimes : [String:String]  
// Specifies both the key and the value would be of type string

An example for using an associative array / dictionary could be to store the subject code with the subject name:

var  myCourse : [String:String] = ["CP1001":"Computing Basics", "FP1001":"Finance Basics", "CP2002":"Algorithms"]

Then, we can simply get the subject name using the following code:

var theSubject = myCourse["CP1001"]
println("The subject name for CP1001 is (theSubject!)")

var _CODE_ = "CP1005"
println("The subject name for CP1001 is (myCourse[_CODE_])")

if let invSubject = myCourse["CPxxxx"] {
    println("The invalid subject is (invSubject)")
}

The functions to work with dictionary variables are similar to the ones available with arrays, including the isEmpty and the count functions.

Adding values

In a dictionary object, new values can be added by simply specifying the value for a key:

myCourse["OZ1001"] = "Custom Subject"
Replacing values

This would replace the value that has the key CP1001 with this new text:

myCourse["CP1001"] = "Basics of Computing"

Another alternative for replacing a value in the dictionary object is using the updateValue function and pass the forKey parameter as the key:

myCourse.updateValue("Basics of Finance", forKey:"FP1001")
Removing Values

To remove a value from the dictionary, either set the value of the key to nil or use the function removeValueForKey:

myCourse["CP2002"] = nil
myCourse.removeValueForKey("CP1001")
myCourse.removeValueForKey("LP1001") // Non existent key-value

The function returns the value being removed or nil if none existed.

Iterating values

The elements in a dictionary object can be iterated using the for loop:

for (key, value) in myCourse {
  println("The key :(key) has a value of : (value)")
}

Each item in a dictionary object is returned as a tuple (key, value) and all of the keys, or all of the values can also be accessed as arrays:

var allKeys = myCourse.keys.array
var allValues = myCourse.values.array

Tuples

Tuples are a simple concept. It is a data structure that holds multiple parts. The values inside of a tuple can be of the same type or different types. Declaring a tuple is easy and can be defined as TupleName and the value parts inside brackets:

var webError = (Int, String)
webError = (404, "Page not found")
var myTuple = ("07:00", "Morning Run", true)

Accessing the members of a tuple

To access the members of a tuple, the values can be stored into normal variables. This reverse assignment is called decomposition:

var (errorCode:Int, errorDescription:String) = webError

Since tuples are not arrays or dictionary objects, they cannot be accessed using indices, sequences, or associates. In such a scenario, Swift creates sequential member properties that allow access to the tuple members:

println("The components of webError are code: (webError.0) and Description: (webError.1)")

Named access to tuple members

It is not always very easy to use the sequential members to access tuples. How would you know what was .0 and what was .1, this is where named members make the access easier. Creating named members just involves defining a name for the tuple members:

var namedError = (code:200, description:"OK")
println("The components of named error are code : (namedError.code) and description : (namedError.description)")

These components can now be accessed using the named members, as follows:

var theCode = namedError.code        // returns the error code

Strings

Working with strings is also quite easy in Swift. Like arrays, strings can be iterated using a for loop:

var testing = "This is a test"
for char in testing {
  println("The char is (char)")
}

Appending strings

The + and += operators can be used to concatenate strings:

var strSmall = "Small "
strSmall = strSmall + "string "
strSmall += "with added text"

Formatting strings

Like the println function, strings can be formatted and stored in strings instead of using them for printing:

var theStr = "The test string"
var length = countElements(theStr)
var strRes = "The length of (theStr) is (length)"
println(strRes)

Any and AnyObject

Any needs to be mentioned, as it is a type that matches any of the types. This is useful to store a type that could change:

var someValue:Any = "Frogs"
someValue = 6
someValue = "Green Tree Frogs"

If instead of using the Any type in the preceding example, you used something like this:

    var stringValue = "Green Frogs"
    stringValue = 6

Then Playgrounds would complain, as the stringValue variable has been implicitly defined as String. Assigning an integer value to a string variable is not acceptable. This functionality allows Xcode to be typesafe and ensures that even before you run your code, you are accidentally assigning wrong value types to the variables. The Any variable type is similar to id in Objective-C:

    var  castedString = someValue as String 
    // the last value of someValue was "Green Tree Frogs"

The AnyObject type is similar to the Any variable type and the values need to be cast to a specific type to work with. If a value is of type Any and you compare it to a String, it would not work because type Any is not the same as type String and there is no function that compares these two using the == operator. So, it must be cast to a variable of type String and then it could be easily compared.

Control flows and code execution

Like the C variants, Swift offers a series of control flow options that allow conditional execution or multiple executions of other statements. Swift has most of the C-type constructs providing the familiar for loops, if..else, switch, and a couple of newer ones.

The if statement

The classic if statements are available in Swift, and the commands that need to be executed if the condition evaluates to true or false is enclosed in curly brackets:

var berry = "black"
if berry == "red" {
 println ("This is not a blackberry")
}

We see that the condition does not evaluate to true as the value in the variable called berry is black and we are checking it for red. So we do not see any output.

The if..else statement

The if statement also has functionality to do something when the condition does not evaluate to true. So, it basically has two sets of statements; one that evaluates when the condition is true and the other when it does not:

var numApples = 3
if numApples > 5 {
  println("You have enough Apples")
} else {
  println("You might want to buy some more Apples")
}

The if..elseif..else statement

Sometimes, there are more than a single if..else type conditions. In cases where you need more than two conditions, we use the if..elseif..else statement:

var platform = "MAC"
if platform == "MAC" {
  println("This is running Apple OS X")
}else if platform == "WIN" {
  println("This is running Microsoft Windows")
}else{
  println("This could be running Linux")
}

We can add more else if statements to check for more conditions.

The ternary operator

The ternary operator ?: is also referred to as the Elvis Operators since it looks like Elvis' hairdo in ASCII. This is the shortcut for an if...else condition and can be used as follows:

var eggs = 0
var bread = eggs > 0 ? 12 : 1

This checks for a condition, and if it is true, evaluates to the statement between ? and :, and if the condition is not satisfied, it evaluates to the statement after the :.

For loops

When you want to perform some statements repeatedly, you can use loops. This makes it easy rather than write them several times over.

The for-increment loop

The classic for loop is for-condition-increment loop:

for var i=0; i<=10; i++ {
  println("The value of i is (i)")
}

You can also have multiple assignments or increments in the preceding for loop, as shown:

for var i=0, j=0, k=0; i<=10; i++, j--, k+=5 {
  println("The value of i=(i) j=(j) k=(k)")
}

The for-in loop

The new for loop added in Swift is the for-in loop that we have already seen in use earlier for enumerating arrays, and with strings. The for-in loop provides a range of values for the loop to iterate through.

Using for with strings

The following is an example of using the for loop with strings:

for i in "Hello" {
  println("The value of i = (i)")
}

Using for with numeric ranges

The following is an example of using the for loop with numeric ranges:

for i in 1...10 {
  println("The value of i = (i)")
}

Swift has the concept of half closed and full closed ranges. The preceding example is a full closed range that prints the value of i from 1 through to 10:

for i in 1..<10 {
  println("The value of i = (i)")
}

This would print the values of i from 1 to 9, not including the last value that we specified of 10.

Stepped ranges

While we can create ranges with the three dots operator (...), we can create these stepped ranges or strides using the stride functions:

for i in stride(from:1, through:20, by:3){
 println("The value of i = (i)")
}

The other alternative stride function is stride(from:1, to:20, by:3).

Note

The stride function with the through parameter is ... (full closed range) and the function with the to parameter is ..< (half closed range).

The While loop

The other alternative to for loops is a while loop; this performs the statements repeatedly as long as the condition provided evaluates to true, as shown in the following code

var coins = 0
while coins < 10 {
  coins += 1
  println("We have mined (coins) coins")
}

This will run and keep incrementing our coins, and when it reaches the value of 10, it stops, as our condition is that the coins should be less than 10, so the maximum coins we should have are 9. However, because when the value of coins is 9, the while condition is evaluated as true and run once again, incrementing our coins count to 10.

There is a variation on the while condition and that is the do..while loop. The difference between the while loop and the do..while loop is that the while loop may or may not execute, depending on the condition; whereas the do..while loop will execute at least once before evaluating the condition to determine running the code or not:

coins = 0
do {
  coins += 1
  println("We have mined (coins) coins")
}while coins < 10

We find that the loop ran once again and now we have 10 coins. When the value of coins reaches 10, the loop is stopped and not executed again.

Seeing the two variations, be careful when you use them, they could give you unexpected results due to the way they work.

The switch condition

The if statement works with conditions and mostly we use a series of if statements to check for the value of a variable. switch is a better approach that allows checking for multiple values.

var age1 = 28
switch age1 {
  case 0:
   println("Baby")
  case 1:
   println("Toddler")
}

This code would cause the compiler to complain, especially since the Swift compiler attempts to reduce programming errors. We have the code that is not faulty, but we have not handled the scenario where none of the cases are matched as in the preceding example. Swift expects a default value to handle the other scenarios that do not match. The working code would look like this:

var age1 = 28
switch age1 {
  case 0:
   println("Baby")
  case 1:
   println("Toddler")
 default:
  println("Others")
}

If we were to classify the ages, it would be quite a hassle to type in every possible match, we might just want that 1 to 3 be a toddler and 4 to 12 be a child, as shown ahead:

var age1 = 28
switch age1 {
  case 0:
   println("Baby")
  case 1, 2, 3:
   println("Toddler")
 case 4, 5, 6, 7, 8, 9, 10, 11, 12:
 println("Child")
 default:
  println("Other")
}

This is a bit tedious, typing in all of the values. Swift helps us out here with ranges, we can use the range operator ... (three dots) as shown in the following code:

var age1 = 28
switch age1 {
  case 0:
   println("Baby")
  case 1...3:
   println("Toddler")
  case 4...12:
   println("Child")
  case 13...19:
   println("Teen")
  default:
   println("Other")
}

We can also use non-contiguous ranges, such as 0 to 17 and 60 to 99 in this example to segregate them as working and non-working population:

var age1 = 28
switch age1 {
  case 0...17, 60...99:
   println("Not Working")
default:
   println("Working")
}

The switch statement can handle pretty much any type of value, not just numeric. It can handle strings, tuples, and many more.

var berry1 = "red"
switch berry1 {
  case "red" :
    println("This is a red berry")
  case "blue" :
    println("This is a blue berry")
  case "black" :
    println("This is a black berry")
  default
    println("This is a not a berry")
}

Character ranges can also be used like "a"..."i", "l"..."x".

Tuples can also be used for switch case matching:

var aScore = (100, "Temple Bun")
switch aScore {
  case (1000, "Temple Bun"):
  println ("You made the high score")
  default:
  println("A little more (1000-aScore.0) and you can beat the high score")
}

With tuples, you can choose to ignore a value, that is, say you wanted to check the scores of a particular game or just a particular score for any game, as in the following code:

switch aScore{
  case (_, "Temple Bun"):
    println("Wow, I could never score on this game")
  case ( 100, _):
    println("Yay! You are a player… I have not yet tried (aScore.1)")
  default:
    println("All play makes Jack a dull boy")
}

There are a couple more tricks with Swift. In the previous example, since our score is 100, the first condition matches and it prints out the "Wow, I could never …" message. This is the default behavior, and the expected one too. In some cases, you might want it to continue matching the next case. In such a scenario, you can use the fallthrough keyword. By default, the code exits the switch block and does not check the next case, with fallthrough, the statements for the next case are also executed, irrespective of the match, as shown here:

switch aScore{
  case (_, "Temple Bun"):
    println("Wow, I could never score on this game")
    fallthrough
  case ( 100, _):
    println("Yay! You are a player… I have not yet tried (aScore.1)")
  default:
    println("All play makes Jack a dull boy")
}

Now, we will see both the messages, "Wow, I could…" and "Yay! You are a …".

In another example, we can see this:

var theNumber = 1
switch (theNumber) {
  case 1:
    println("One")
    fallthrough
  case 2:
    println("Two")
  case 3:
    println("Three")
  default:
    println("Default")
}

You will see that in the output it prints One and Two. This is useful in cases where you might want to only execute println("Two") if theNumber is 2, but display both One and Two if it is 1.

Note

If you need to exit a loop or a switch, the break statement exits the current scope and continues execution.

In the examples, you will notice that we used aScore.0 or aScore.1 to access the first or the second member of the tuple. This is fine, but sometimes you want to access them with a proper variable name. We can do this via value binding, and use it as follows:

switch aScore{
  case (let score, "Temple Bun"):
    println("Wow, I could never score (score) ")
  case ( 100, let game):
    println("Yay! You are a player… I have not yet tried (game)")
  default:
    println("All play makes Jack a dull boy")
}

switch is even more powerful in Swift and it offers more condition checking options via the where clause:

var marks = (80, "Math")
switch marks {
  case (let score, let subject) where score>75 && subject == "Math" :
    println("You got a HD in Math")
  case (50..<80, let subject):
   println("You passed the subject (subject)"
  case (let score, let subject):
   println("You scored (score) in (subject)")
  default:    
   println("")
}

Tip

You can also check for compound cases, such as switch score + bonus in one go, or use functions to check conditions.

Functions

Functions in Swift are declared using the func keyword. A function encloses a set of statements inside a block. When a function is called, all of the statements inside that block that make up the function are executed.

Return values

Functions may or may not return any values. Although, functions in Swift can return multiple values via tuples.

The no-return value function

The following is an example of a no-return value function:

func noValues(){
 println("this returns no values")
}

The single-return value function

The following is an example of a single-return value function:

func returnOne() -> Int{
 return 1
}
var one = returnOne()

You might note that when a function returns a value, we need to specify the return type of the value and that the function is written with a -> at the end followed by the return type.

The multiple-return value function

The following is an example of a multiple-return value function:

func returnMany() -> (Int, String){
  return (404, "Page not found")
}
var error = returnMany()

The multiple return values are in the form of a tuple and it is imperative to define the return values. In the previous example, we return an Int and a String value. While in this example, we are returning the tuple without named parameters; depending on your needs, you could return tuples with named parameters.

Parameters

Functions might accept parameters that allow you to pass values that may influence the functionality of the function. We have seen examples of functions that do not require any parameters in the previous examples. If we need to pass parameters, we need to specify the type of the parameter value we shall pass to the function.

The single parameter function

The following is an example of a single parameter function:

func strLength(theStr:String) -> Int {
  return countElements(theStr)
}
var len = strLength("Hello World")

The multiple parameter function

The following is an example of a multiple parameter function:

func multiplyBy(num1:Int, num2:Int) -> Int {
  return num1 * num2
}
var res = multiplyBy(7, 4)

Named parameters

You might have noticed that we pass parameters to the functions, but as a developer you might want to have named parameters that would be self-explanatory as to what the parameters are. It would not be very clear on the purpose of the parameters passed. To name the parameters, we need to give them a name. These are called external parameter names, the internal names are used by the function:

func appendString(theString first: String, withString second: String) -> String {
    return "(first) (second)"
}

var strRes = appendString("Hello", "World!")

The preceding code will give a compiler error because appendString was declared to use named functions and it is missing the named arguments of first and second. To be able to call the appendString function, we need to use the named parameters:

var strRes = appendString(theString:"Hello", withString: "World!")

Shorthand external parameter names

Swift has a shorthand method that helps avoid this scenario by simply using a hash symbol (#). This ensures that both the parameters (internal and external) have the same name. The following code explains this:

func appendStrings(#theString: String, #withString: String) -> String {
    return "(theString) (withString)"
}
var theBook = appendStrings(theString: "Swift", withString: "Rocks")

Optional parameters with default values

For some functions, you can also provide default values that allow you to omit passing that parameter:

func replicate(times:Int, theString:String = "-")->String{
  var result = ""
  for i in 1...times {
  result += theString
  }
  return result
}
var dashes = replicate(20)

This calls the replicate function and passes 20 for times and a value of "-" as theString. If we want to call this function with a different string to replicate, we cannot simply call it as follows:

var plusses = replicate(20, "+")

This would give an error and to fix it, we need to call it as follows:

var plusses = replicate(20, theString:"+")

Passing multiple parameters

While we can have functions with no parameters, we could also have functions with single or multiple parameters; but in some cases, there might be a scenario to pass an unknown number of parameters. With a known number of parameters, we can define the number of parameters. With unknown, we would never know if there will be any parameters and if there are; the number of parameters would be unknown. These are called parameter arrays or variadic parameters. This is denoted by three dots ... after the parameter type, as indicated in the following code:

func add(numbers:Int...)->Int{
  var result = 0
  for i in numbers{
    result += i
  }
 return result
}
var total = add(3, 7, 2, 9, 12, 11)        // 44

Note

You can have only one variadic parameter in a function and it must be at the last position in the list of parameters.

Tip

There are more advanced features associated with functions. This chapter is a quick intro to Swift and hence they are not covered here. Please refer to a Swift book for comprehensive coverage of advanced features such as in-out parameters, constant and variable parameters, function types, and using functions as return types. Apple has a free book called The Swift Programming Language that you can download and refer to, among other options.

Using closures

Closures might sound like a fanciful name but in simple terms, they are what Apple introduced as Blocks for Objective-C. This is functional code that can be called at a later time. These retain their own scopes for variables and contained functions and can be executed in a different scope than they were created in. These are so called because they form an enclosure over the variables and constants, as shown in the following code:

func startFrom(startValue:Int) -> (()->Int) {
  var _startVal = startValue
  func increment() -> Int{
    return ++_starVal
  }
  return increment
}

In the previous example, we return a function and if you noticed the return type, it is (()-> Int), which specifies that the return type is a function. This function takes no parameters and returns an Int value. First, we save the value passed into a local variable called _startVal. Then we return the value while incrementing it using ++_startVal as shown here:

var counter1 = startFrom(1)
var counter2 = startFrom(10)
counter1()                // return  2
counter2()                // return 11

The preceding example demonstrates that both of the counter functions contain their own set of variables and are independent of each other.

Objects

Swift has an object-oriented paradigm for you to declare and create classes, structures and enumerations. The primitives such as Int, String, Float, Double, to name a few, are structures or structs as they are now called.

Classes

To define a class, we simply use the keyword class. A class can contain variables, functions and methods that have initializers to set up the initial values; they can be extended and they can also conform to protocols to provide standard functionality. The following code explains this:

class Stooge{
 var name:String = ""
  func getName() -> String{
    return self.name
  } 
}
var stooge1 = Stooge()
stooge1.name = "Moe"
println("The name of the first stooge is (stooge1.getName())")

This is a bit cumbersome. What if we could initialize our object with a default name? How about using the following:

var stooge2 = Stooge("Larry")

We get a compiler error. To be able to use it this way, we need to create initializers using the init function. Our Stooge class would need modifications, and will now look something like the following code snippet:

class Stooge{
    var name: String = ""

    func lengthName() -> Int {
        return countElements(self.name)
    }
    
    init(forName: String){
        self.name = forName
    }
}

However, we still get a compiler error and this time the compiler tells us that it is looking for a named parameter name. So we cannot simply call this as Stooge("Larry"); instead, we need to call it as Stooge(forName:"Larry").

Swift provides us a way to ignore the external name by adding an underscore before the internal name. Then we can call this without the forName: parameter:

init(_ forName:String){
  self.name = forName
}

And now, we can initialize our new stooge variable as follows:

var stooge2 = Stooge("Larry")

Properties

We created a property called name in the previous example, and it can be read and updated directly. Say we add another property in the year of first appearance as:

class Stooge{
 var name:String
 var firstAppear:Int 

init(_ forName:String){
  self.name = forName
  self.firstAppear = 1900
}

convenience init(){
  self.init("Unknown")
}

convenience init(_ forName:String, _ year:Int){
  self.init(forName)
  self.firstAppear = year
}

 func lengthName() -> Int {
        return countElements(self.name)
    }
  }

We have two convenience functions for init. The convenience functions are defined to allow different function signatures. In our case, we can call the init function without any parameters, with just the name or with both, the name and the year. If we did not use the convenience keyword, the compiler would complain thinking we are redefining the function with a new signature:

var stooge3 = Stooge("Moe", 1934)

The properties in this class, name and firstAppear, are both directly accessible. You could also define setters and getters that could be used to set the values as required. These are useful as calculated properties:

  var theYear:Int {
    get {
      return self.firstAppear - 1900
    }
    set {
      self.firstAppear = newValue + 1900
    }
  }

We could now use this like a property and it will interact and set/get the value from the firstAppear variable:

println("(stooge3.firstAppear)")  // Prints 1934
stooge3.theYear = 67
println("(stooge3.firstAppear)")  // Prints 1967

Tip

If you want to run some code before a value is set or after a value is set, Swift offers the willSet and the didSet functions like the get and set.

Note

Structures are similar to classes in most regards whereby they can have properties, functions, initializers, and so on. One of the differences between structures and classes in Swift is that structures are copied and do not use reference counting.

Enumerations

Enumerations are data types that have named values and behave like constants. They too, like structures and classes, have properties and functions associated including initializer functions:

enum eStooges:Int{
  case Moe = 1
  case Larry
  case Curly
  case Shemp
  case Joe
}
var aStooge = eStooges.Moe

You could add a function to this like toString, which returns the name of Stooge as a string:

enum eStooges:Int{
  case Moe = 1
  case Larry
  case Curly
  case Shemp
  case Joe

  func toString()->String{
    switch self{
     case .Moe:
      return "Moe"
     case .Larry:
      return "Larry"
     case .Curly:
      return "Curly"
     case .Shemp:
      return "Shemp"
     case .Joe:
      return "Joe"
    }
  }
}
var aStooge = eStooges.Moe
println(aStooge.toString())    // Moe

You can also use the enumerations without the enumeration name directly with the member name, like this:

var theStooge: eStooges = .Curly
println("(theStooge.toString())")      // Curly
println("(theStooge.rawValue)")        // 3

Tip

When using enumerations, it will always number them starting from 0, however, if you want to change that start index, you can define the first value and the rest will be assigned a sequential value. You can also assign values to each of the members or they are assigned the next number (that is, sequential).

Extensions – extending the classes

This is one of the most interesting language features in Swift. It allows adding of functions and features to an existing class. We can extend an Int variable and add an extension called "square" that returns the square of the integer:

extension Int{
  var square:Int {
    return self * self
  }
}

You can now type 4.square in the Playground and the result 16 will show.

We can create another extension for strings called reverse:

extension String {
  var reverse:String{
    var result:String = ""
    for i in self {
      result = String(i) + result
    }
    return result
  }
}
"Hello".reverse        // shows olleH

Operator overloading

We can use most of the basic operators to perform basic operations, as you have seen in the previous examples. With Swift, we can also re-declare these operators to perform custom operations. Some of the basic operators can be overridden to provide additional functionality.

There are three positions for operators, prefix, postfix, and infix. They are defined depending on the position of where the operator lies.

The prefix operator

Prefix operators are those that have the operator before the expression, such as ++a or !b. Here's an example of using the square root symbol operator () and making it function as expected:

prefix operator √ {}
prefix func √ (theNumber:Double) -> Double {
  return sqrt(theNumber)
}
var sqRoot1 = √144        // 12.0
var sqRoot2 = √16         // 4.0

The postfix operator

Postfix operators appear at the end of the expression, such as a++. Here is an example of using the % postfix operator that returns the percentage:

postfix operator %{}
postfix func %(theNumber: Double) -> Double {
    return theNumber / 100
}

var rads1 = 60%         // 0.6
var rads2 = 152%        // 1.52

The infix operator

The infix operator appears in between two expressions, such as the equality operator == or +=, or >>, << and the bitwise operators &&, ||,. Let us create a custom infix operator that replicates a string as many times as the number following it:

infix operator ** {}
func ** (theString:String, times:Int) -> String{
  var res = theString
  for i in 1..<times {
    res += theString
  }
  return res
}
var buffer = "Hello" ** 5    //HelloHelloHelloHelloHello
..................Content has been hidden....................

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