├── .gitignore ├── README.md ├── swift_10_structures.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ └── contents.xcworkspacedata ├── swift_11_classes.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ └── contents.xcworkspacedata ├── swift_12_class_Inheritance.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ └── contents.xcworkspacedata ├── swift_13_protocols.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ └── contents.xcworkspacedata ├── swift_14_generics.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ └── contents.xcworkspacedata ├── swift_15_optionals.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ └── contents.xcworkspacedata ├── swift_16_closures.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ └── contents.xcworkspacedata ├── swift_17_extensions.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ └── contents.xcworkspacedata ├── swift_18_error_handling.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ └── contents.xcworkspacedata ├── swift_1_variables.playground ├── Contents.swift ├── contents.xcplayground ├── playground.xcworkspace │ └── contents.xcworkspacedata └── timeline.xctimeline ├── swift_2_basic_types.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ └── contents.xcworkspacedata ├── swift_3_operators.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ └── contents.xcworkspacedata ├── swift_4_collection_types.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ └── contents.xcworkspacedata ├── swift_5_conditional_logic.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ └── contents.xcworkspacedata ├── swift_6_looping.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ └── contents.xcworkspacedata ├── swift_7_functions.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ └── contents.xcworkspacedata ├── swift_8_functions_advanced.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ └── contents.xcworkspacedata └── swift_9_enumerations.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace └── contents.xcworkspacedata /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode playground projects 2 | .DS_Store 3 | xcshareddata 4 | xcuserdata 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # swift-hack-pack 2 | The swift-hack-pack is a collection of Swift Playground files that teach Apple's new Swift programming language. It's based on Swift 2.2 and Xcode 7.3.1 3 | 4 | It was designed as free course material for the Guild of Software Architects Meetup group: 5 | 6 | http://www.meetup.com/guildsa-frisco/ 7 | -------------------------------------------------------------------------------- /swift_10_structures.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import UIKit 3 | 4 | // Structures allow us to group variables and functions together as a new type 5 | // that can be used in the same way as the built-in types that Swift provides 6 | // for us. 7 | 8 | // Here's an example of new type called Player which groups together a bunch 9 | // of variables which each player in the game should have. 10 | struct Player { 11 | 12 | var weapon: String 13 | var attackDamage: Int 14 | var healthPoints: Int 15 | } 16 | 17 | // All structures have an automatically-generated member-wise initializer, 18 | // which we can use to initialize the member properties of new structure 19 | // instances. Initial values for the properties of the new instance can 20 | // be passed to the member-wise initializer by name: 21 | 22 | var player1 = Player(weapon: "Club", attackDamage: 10, healthPoints: 100) 23 | var player2 = Player(weapon: "Sword", attackDamage: 15, healthPoints: 75) 24 | 25 | // We can also access our new type's member variables and change them if we wish. 26 | player1.weapon = "Ax" 27 | player1.attackDamage = 15 28 | 29 | //------------------------------------------------------------------------------ 30 | 31 | // Initializers 32 | 33 | // If we don't like the automatically-generated Member-wise Initializer, we can 34 | // define our own Initializers by adding one or more version of the init method. 35 | // But, once you define a custom Initializer, we can no longer use the 36 | // automatically-generated Member-wise Initializer. If we want a custom init 37 | // and a Member-wise Initializer, we will have to manually define both. 38 | 39 | struct Color { 40 | 41 | let red, green, blue: Float 42 | 43 | init(red: Float, green: Float, blue: Float) { 44 | self.red = red 45 | self.green = green 46 | self.blue = blue 47 | } 48 | 49 | init(white: Float) { 50 | red = white 51 | green = white 52 | blue = white 53 | } 54 | } 55 | 56 | // Both initializers can be used to create a new Color instance, by providing 57 | // named values for each initializer parameter: 58 | 59 | // Create a new Color instance by setting all three color properties at once. 60 | let purple = Color(red: 1.0, green: 0.0, blue: 1.0) 61 | 62 | // Create a new Color instance that is gray-scaled by setting only a white value. 63 | let gray = Color(white: 0.5) 64 | 65 | //------------------------------------------------------------------------------ 66 | 67 | // Methods 68 | 69 | // Methods are functions that are associated with a particular structure or 70 | // class. These methods are typically designed to modify the variables held by 71 | // the structure or class that defines them. 72 | 73 | // For example, if we're making a game that has a lot of enemies for our 74 | // players to fight, it would make sense to create a new type to represent 75 | // these enemies which not only includes their data but methods that allow 76 | // us to modify that data. 77 | 78 | struct Enemy { 79 | 80 | var weapon: String = "Club" 81 | var attackDamage: Int = 5 82 | var healthPoints: Int = 100 83 | 84 | init() { 85 | print("New Enemy Initialized with default values!") 86 | } 87 | 88 | init(weapon: String, damage: Int, health: Int) { 89 | print("New Enemy Initialized with custom values!") 90 | self.weapon = weapon 91 | self.attackDamage = damage 92 | self.healthPoints = health 93 | } 94 | 95 | func attack() { 96 | print("Enemy attacks with \(weapon) for \(attackDamage) points of damage!") 97 | } 98 | 99 | mutating func applyDamage(damage:Int) { 100 | healthPoints -= damage 101 | print("HealthPoints reduced to \(healthPoints)") 102 | } 103 | } 104 | 105 | var enemy1 = Enemy() 106 | 107 | enemy1.attack() 108 | enemy1.applyDamage(damage: 15) 109 | 110 | var enemy2 = Enemy(weapon: "Sword", damage: 25, health: 100) 111 | 112 | enemy2.attack() 113 | enemy2.applyDamage(damage: 5) 114 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /swift_10_structures.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /swift_10_structures.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /swift_11_classes.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | //------------------------------------------------------------------------------ 3 | 4 | // Now that we've covered all the basics of working with variables and 5 | // functions we can start to understand the more advanced concepts of Swift such 6 | // as its support for Object Oriented Programming or OOP. 7 | 8 | // As the name implies, Object Oriented Programming is all about building our 9 | // programs out of Objects and to create these Object we will use a Swift keyword 10 | // called "class". 11 | 12 | // A class allows us to group variables and functions together as a new type. 13 | // Basically, it can be thought of as a blueprint that tells Swift how to create 14 | // or build the objects that we need for our program. 15 | 16 | // The three main features of Object Oriented Programming are: 17 | 18 | // 1 - Encapsulation 19 | // 2 - Inheritance 20 | // 3 - Polymorphism 21 | 22 | //------------------------------------------------------------------------------ 23 | 24 | // Classes 25 | 26 | // Just like Structures, Classes allow us to group variables and functions 27 | // together as a new type. Matter of fact, Structures and Classes have so much 28 | // in common we can simply change the "struct" keyword on our Enemy structure 29 | // into "class", and we now have an Enemy class. 30 | 31 | class Enemy { 32 | 33 | var weapon: String = "Club" 34 | var attackDamage: Int = 5 35 | var healthPoints: Int = 100 36 | 37 | init() { 38 | print("New Enemy Initialized with default values!") 39 | } 40 | 41 | init(weapon: String, damage: Int, health: Int) { 42 | print("New Enemy Initialized with custom values!") 43 | self.weapon = weapon 44 | self.attackDamage = damage 45 | self.healthPoints = health 46 | } 47 | 48 | deinit { 49 | // If required, perform deinitialization here! 50 | print("Enemy Deinitialized!") 51 | } 52 | 53 | func attack() { 54 | print("Enemy attacks with \(weapon) for \(attackDamage) points of damage!") 55 | } 56 | 57 | func applyDamage(damage:Int) { 58 | healthPoints -= damage 59 | print("HealthPoints reduced to \(healthPoints)") 60 | } 61 | } 62 | 63 | var enemy = Enemy() 64 | 65 | print(enemy.weapon) 66 | print(enemy.attackDamage) 67 | print(enemy.healthPoints) 68 | 69 | enemy.attack() 70 | enemy.applyDamage(damage: 10) 71 | 72 | 73 | var bossEnemy = Enemy(weapon: "Magic Sword", damage: 35, health: 200) 74 | 75 | print(bossEnemy.weapon) 76 | print(bossEnemy.attackDamage) 77 | print(bossEnemy.healthPoints) 78 | 79 | bossEnemy.attack() 80 | bossEnemy.applyDamage(damage: 10) 81 | 82 | //------------------------------------------------------------------------------ 83 | 84 | // Since Structures and Classes are so similar, lets list the additional 85 | // capabilities and benefits gained by using class over struct: 86 | 87 | // 1. Classes support inheritance which allows one class to inherit the 88 | // characteristics of another. 89 | 90 | // 2. Classes support Deinitializers which allow an instance of a class 91 | // to free up any resources it has assigned. 92 | 93 | // 3. Objects created from Classes are passed into functions as references 94 | // which and can be changed in an intuitive way, while objects created from 95 | // Structures are always passed as copies that can not be changed. 96 | 97 | 98 | -------------------------------------------------------------------------------- /swift_11_classes.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /swift_11_classes.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /swift_12_class_Inheritance.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | //------------------------------------------------------------------------------ 3 | 4 | // Inheritance 5 | 6 | // A class can inherit methods, properties, and other characteristics from 7 | // another class. When one class inherits from another, the inheriting class 8 | // is known as a subclass, and the class it inherits from is known as its 9 | // superclass. 10 | 11 | // Our Enemy class below defines simple enemies that our players can fight. 12 | // We've already covered this class in the last lecture. 13 | 14 | class Enemy { 15 | 16 | var weapon: String = "Club" 17 | var attackDamage: Int = 5 18 | var healthPoints: Int = 100 19 | 20 | init() { 21 | print("New Enemy Initialized with default values!") 22 | } 23 | 24 | init(weapon: String, damage: Int, health: Int) { 25 | print("New Enemy Initialized with custom values!") 26 | self.weapon = weapon 27 | self.attackDamage = damage 28 | self.healthPoints = health 29 | } 30 | 31 | func attack() { 32 | print("Enemy attacks with \(weapon) for \(attackDamage) points of damage!") 33 | } 34 | 35 | func applyDamage(damage:Int) { 36 | healthPoints -= damage 37 | print("HealthPoints reduced to \(healthPoints)") 38 | } 39 | } 40 | 41 | //------------------------------------------------------------------------------ 42 | 43 | // Now, for the next version of our game, we want to add a new type of enemy 44 | // that uses magic. We could add new properties and methods to the Enemy class 45 | // so all enemies can use magic, but that's a waste of memory since only the 46 | // new Warlock enemies really need them. 47 | 48 | // But if we create a new class called Warlock that inherits from Enemy, we can 49 | // use everything in Enemy and add just the new variables and methods that are 50 | // required to keep track of magic data. 51 | 52 | class Warlock : Enemy { 53 | 54 | var spellDamage: Int = 10 55 | var magicPoints: Int = 500 56 | 57 | override init() { 58 | 59 | // This will call the init in Enemy so it sets all of its defaults 60 | // before we alter any of them. 61 | super.init() 62 | 63 | print("New Warlock Initialized with default values!") 64 | 65 | weapon = "Magic Staff" 66 | attackDamage = 25 67 | } 68 | 69 | override func attack() { 70 | print("Warlock attacks with \(weapon) for \(attackDamage) points of damage!") 71 | 72 | magicPoints -= 5 73 | print("MagicPoints reduced to \(magicPoints)") 74 | } 75 | 76 | func castSpell() { 77 | print("Warlock casts a spell for \(spellDamage) points of damage!") 78 | 79 | magicPoints -= 10 80 | print("MagicPoints reduced to \(magicPoints)") 81 | } 82 | 83 | func teleport() { 84 | print("Warlock teleports to new a position!") 85 | } 86 | } 87 | 88 | var enemy = Enemy() 89 | 90 | print(enemy.weapon) 91 | print(enemy.attackDamage) 92 | print(enemy.healthPoints) 93 | 94 | enemy.attack() 95 | enemy.applyDamage(damage: 10) 96 | 97 | 98 | 99 | var warlock = Warlock() 100 | 101 | print(warlock.weapon) 102 | print(warlock.attackDamage) 103 | print(warlock.healthPoints) 104 | print(warlock.magicPoints) 105 | 106 | warlock.attack() 107 | warlock.applyDamage(damage: 10) 108 | warlock.castSpell() 109 | warlock.teleport() 110 | -------------------------------------------------------------------------------- /swift_12_class_Inheritance.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /swift_12_class_Inheritance.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /swift_13_protocols.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | //------------------------------------------------------------------------------ 3 | 4 | // Protocols 5 | 6 | // A protocol defines a blueprint of methods, properties, and other requirements 7 | // that suit a particular task or piece of functionality. The protocol can then 8 | // be adopted by a class, structure, or enumeration to provide an actual 9 | // implementation of those requirements. Any type that satisfies the requirements 10 | // of a protocol is said to conform to that protocol. 11 | 12 | // -- Property Requirements for Protocols -- 13 | 14 | // If you define a var property with { get } only, then the class, enumeration, 15 | // or structure that uses the protocol can define how it wants to implement 16 | // the property - as either a constant or a variable (i.e var or let keyword). 17 | 18 | // If you define the var property with { get set }, then this can only be 19 | // implemented as a variable (i.e var keyword). If you attempt to use the let 20 | // keyword when you create a class, structure, or enumeration with the protocol, 21 | // Xcode will report an error. 22 | 23 | 24 | // Below is a protocol called Weapon that declares an Int var, a String var and 25 | // a method that must be implemented. 26 | 27 | protocol Weapon { 28 | 29 | // The use of { get } means the class that implements this variable can 30 | // choose to make it either a var or a let constant. 31 | var description: String { get } 32 | 33 | // The use of { get set } means the class that implements this variable can 34 | // only make it a var. 35 | var attackDamage: Int { get set } 36 | 37 | func attack() 38 | } 39 | 40 | // Any class that conforms to the Weapon protocol must implement the methods 41 | // and properties required of Weapon. Below are two classes that conform to 42 | // our Weapon protocol: 43 | 44 | class ShortSword : Weapon { 45 | 46 | let description: String = "A good beginner's Sword." 47 | var attackDamage: Int = 10 48 | 49 | func attack() { 50 | print("The Short Sword slices!") 51 | } 52 | } 53 | 54 | class BattleAx : Weapon { 55 | 56 | let description: String = "An upgrade over the basic Ax, but you need great strength to wield it!" 57 | var attackDamage: Int = 20 58 | 59 | func attack() { 60 | print("The Battle Ax chops!") 61 | } 62 | } 63 | 64 | var myShortSword = ShortSword() 65 | 66 | myShortSword.attack() 67 | print(myShortSword.attackDamage) 68 | print(myShortSword.description) 69 | 70 | var myBattleAx = BattleAx() 71 | 72 | myBattleAx.attack() 73 | print(myBattleAx.attackDamage) 74 | print(myBattleAx.description) 75 | 76 | //------------------------------------------------------------------------------ 77 | 78 | protocol Enchantment { 79 | 80 | // The use of { get set } means the class that implements this variable can 81 | // choose only var or a let constant. 82 | var magicPoints: Int { get set } 83 | 84 | func renderFx() 85 | } 86 | 87 | // Here's an example of a new class that is based on two different protocols. 88 | // This means it must implement everything required by both the Weapon and 89 | // Enchantment protocols. 90 | 91 | class MagicSword : Weapon, Enchantment { 92 | 93 | let description: String = "An upgrade over the Sword, but you need magic to wield it!" 94 | var attackDamage: Int = 20 95 | var magicPoints: Int = 500 96 | 97 | func attack() { 98 | print("The Magic Sword slashes with Awesomeness!") 99 | } 100 | 101 | func renderFx() { 102 | print("Imagine some incredible special effects here!") 103 | } 104 | } 105 | 106 | var myMagicSword = MagicSword() 107 | 108 | myMagicSword.attack() 109 | myMagicSword.renderFx() 110 | print(myMagicSword.attackDamage) 111 | print(myMagicSword.description) 112 | print(myMagicSword.magicPoints) 113 | 114 | -------------------------------------------------------------------------------- /swift_13_protocols.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /swift_13_protocols.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /swift_14_generics.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import UIKit 3 | 4 | //------------------------------------------------------------------------------ 5 | 6 | // Generics 7 | 8 | // Generic code enables us to write flexible, reusable code that can work with 9 | // multiple types. 10 | 11 | // Supose we wrote a function that could swap two Ints around. 12 | 13 | func swapTwoInts(_ a: inout Int, _ b: inout Int) { 14 | let tempA = a 15 | a = b 16 | b = tempA 17 | } 18 | 19 | // This works as expected on two Ints, but what if we wanted to swap two Floats? 20 | 21 | var myInt1 = 10 22 | var myInt2 = 50 23 | 24 | swapTwoInts( &myInt1, &myInt2 ) 25 | 26 | print("After calling swapTwoInts: myInt1 is now \(myInt1), and myInt2 is now \(myInt2)") 27 | 28 | 29 | // We could write a new function that swaps Floats like so: 30 | 31 | func swapTwoFloats(_ a: inout Float, _ b: inout Float) { 32 | let tempA = a 33 | a = b 34 | b = tempA 35 | } 36 | 37 | var myFloat1:Float = 10.5 38 | var myFloat2:Float = 50.5 39 | 40 | swapTwoFloats( &myFloat1, &myFloat2 ) 41 | 42 | print("After call swapTwoFloats: myFloat1 is now \(myFloat1), and myFloat2 is now \(myFloat2)") 43 | 44 | 45 | // Matter of fact, we could write a whole series of functions that allow us to 46 | // swap all the types, but this is a waste since all these functions are 47 | // basically the same code. The only thing that really changes is the type of 48 | // the variables being swapped. 49 | 50 | //------------------------------------------------------------------------------ 51 | 52 | 53 | // Generic Functions 54 | 55 | // Generic functions can work with any type. Here's a generic version of the 56 | // swapTwoInts function from above, called swapTwoValues which can swap any two 57 | // values regardless of the type. 58 | 59 | func swapTwoValues(_ a: inout T, _ b: inout T) { 60 | let tempA = a 61 | a = b 62 | b = tempA 63 | } 64 | 65 | // The generic version of the function uses a placeholder type name instead of 66 | // an actual type name (such as Int, String, or Double). In the example above, 67 | // we're using a 'T' as a stand-in for the type. 68 | 69 | myInt1 = 10 70 | myInt2 = 50 71 | 72 | swapTwoValues( &myInt1, &myInt2 ) 73 | 74 | print("After calling swapTwoValues: myInt1 is now \(myInt1), and myInt2 is now \(myInt2)") 75 | 76 | myFloat1 = 10.5 77 | myFloat2 = 50.5 78 | 79 | swapTwoValues( &myFloat1, &myFloat2 ) 80 | 81 | print("After calling swapTwoValues: myFloat1 is now \(myFloat1), and myFloat2 is now \(myFloat2)") 82 | 83 | var myString1:String = "String #1" 84 | var myString2:String = "String #2" 85 | 86 | swapTwoValues( &myString1, &myString2 ) 87 | 88 | print("After call swapTwoFloats: myString1 is now \(myString1), and myString2 is now \(myString2)") 89 | 90 | -------------------------------------------------------------------------------- /swift_14_generics.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /swift_14_generics.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /swift_15_optionals.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import UIKit 3 | 4 | //------------------------------------------------------------------------------ 5 | 6 | // Optionals with ? 7 | 8 | 9 | // Suppose we were using someone's class and it had two property variables defined 10 | // like this: 11 | 12 | var age: Int? = nil 13 | var height: Int? = 180 14 | 15 | // By adding a '?' immediately after the data type the designer of this class is 16 | // telling the compiler that the variable might contain a number or not. 17 | // In other words, it might be 42 or it might be nil. There's no guarantee! 18 | 19 | // Now, the usage of '?' causes Swift to basically rewrite our code. For example, 20 | // if we declared a var called "weight" and made it optional by adding the '?' 21 | // symbol after the type identifier, Swift would rewrite it like so: 22 | 23 | // var weight: Int? = 200 24 | 25 | var weight: Optional = Optional(200) 26 | 27 | // This means, that the '?' symbol we added is what we call "syntatic sugar" 28 | // since it hides a more complicated version of the code that wraps the type 29 | // in a Generic called Optional. 30 | 31 | //------------------------------------------------------------------------------ 32 | 33 | // Unwrapping with ? and when ! 34 | 35 | 36 | // Since Swift wraps our property variables with the Generic called Optional, 37 | // we will need to un-wrap them later when we want to use them. 38 | // This un-wrapping operation is done using either the '?' or '!' symbols. 39 | 40 | class Weapon { 41 | 42 | var name: String = "Sword" 43 | } 44 | 45 | class Player { 46 | 47 | var health: Int = 100 // The Player always has some health value. 48 | 49 | var weapon: Weapon? = nil // But, the player might not have a Weapon! 50 | } 51 | 52 | 53 | var player1 = Player() // Create our Player. 54 | player1.weapon = Weapon() // Give him or her a Weapon. 55 | 56 | 57 | // Accessing the player's health points works as expected. 58 | print("The player's health is \(player1.health) points.") 59 | 60 | 61 | // But, our attempted access of the weapon's name results in a blatant 62 | // error! We will be unable to compile and run the code until we fix it. 63 | // This is because weapon is an optional property that might be nil and 64 | // since it might be nil, we need to tell Swift how to handle it when 65 | // un-wrapping it for access. 66 | 67 | //print("The player's current weapon is \(player1.weapon.name).") 68 | 69 | 70 | // We can fix this error by using the '!' symbol. When we put a '!' behind 71 | // the property name we're telling the compiler, "I don’t care that this 72 | // property is optional - go head and un-wrap it for access". But, we should 73 | // only use '!' if we're totally sure that this is safe. 74 | 75 | //print("The player's current weapon is \(player1.weapon!.name).") 76 | 77 | 78 | // If we're not sure if the player will have a weapon or not, but we want 79 | // try to access it without triggering a crash, we can use '?' instead 80 | // of a '!'. The '?' behind the property name tells the compiler, "I don’t 81 | // know whether this property contains nil or a value, so: if it has a value 82 | // use it, otherwise just consider the whole expression nil". Effectively 83 | // the ? allows you to use that property but only in the case where it 84 | // is not nil. 85 | 86 | print("The player's current weapon is \(player1.weapon?.name as String?).") 87 | 88 | //------------------------------------------------------------------------------ 89 | 90 | // Optional Binding - Unwrapping Optionals with the "if let" expression 91 | 92 | // Ok, so we can use '!' or '?' to unwrap a property for access, but this only 93 | // works for one access on one line of code. What if we wanted to safely access 94 | // an optional like weapon several times? In this case, we can use an "if let" 95 | // expression. The "if let" conditional expression allows us to check if an 96 | // Optional holds a value, and if it does - the Optional is unwrapped and 97 | // assigned to a constant which allows us to access it repeatably. 98 | 99 | if let weapon = player1.weapon { 100 | print("The player's current weapon is \(weapon.name).") 101 | } else { 102 | print("The player is unarmed!") 103 | } 104 | 105 | //------------------------------------------------------------------------------ 106 | 107 | // Old-Fashioned, Explicit check for nil. 108 | 109 | // This is not typically done anymore, but is a valid possibility that you may 110 | // see in older code. 111 | 112 | if player1.weapon != nil { 113 | 114 | let unwrappedWeapon = player1.weapon! 115 | 116 | print("The player's current weapon is \(unwrappedWeapon.name).") 117 | } 118 | 119 | -------------------------------------------------------------------------------- /swift_15_optionals.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /swift_15_optionals.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /swift_16_closures.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import UIKit 3 | import PlaygroundSupport // Needed to support asynchronous code in this sample. 4 | 5 | //------------------------------------------------------------------------------ 6 | 7 | // Closures 8 | // 9 | // Just like functions, closures are self-contained blocks of code, but they 10 | // can be assigned to variables and passed into functions. Closures in Swift 11 | // are similar to lambda functions in other programming languages or blocks 12 | // in Objective-C. 13 | 14 | 15 | // A function is basically just a closure that is named. 16 | func sayHelloFunc() { 17 | print("Function says, Hello!") 18 | } 19 | 20 | // Here we use the function. 21 | sayHelloFunc() 22 | 23 | 24 | // Below is a variable that points to a closure. It looks a little weird but 25 | // the variable's type is this: 26 | // 27 | // () -> () 28 | // 29 | // Which means the variable's type is a closure that takes no arguments 30 | // and returns no values. 31 | 32 | var sayHelloClosure: () -> () = { 33 | print("Closure says, Hello!") 34 | } 35 | 36 | // Now, even though sayHelloClosure is a variable, it does point to a closure 37 | // which is a block of code and therefore can be called just like a function. 38 | 39 | sayHelloClosure() 40 | 41 | //------------------------------------------------------------------------------ 42 | 43 | // Here's another function that has two parameters and a return type: 44 | 45 | func combineTextFunc(text1: String, text2: String) -> String { 46 | 47 | return text1 + text2 48 | } 49 | 50 | print(combineTextFunc(text1: "Text combined by a ", text2:"function!")) 51 | 52 | 53 | // Again, we'll create a variable that points to a closure which is capable of 54 | // doing the same thing as the combineTextFunc function above. Note the 55 | // variable's type: 56 | // 57 | // (String, String) -> String 58 | // 59 | // Which means the variable's type is a closure that takes two arguments 60 | // of type String and returns a String. 61 | 62 | 63 | var combineTextClosure: (String, String) -> String 64 | 65 | 66 | // Later, we can initialize the 'combineTextClosure' var by assigning a 67 | // closure to it, but the syntax will look a bit different than we saw 68 | // above because we now must deal with parameters. 69 | 70 | combineTextClosure = { (text1: String, text2: String) -> String in 71 | 72 | return text1 + text2 73 | } 74 | 75 | // We could also initialize it like this where the () are dropped, the 76 | // parameter types are infered, and a call to return is just assumed 77 | // upon reaching the last line. 78 | 79 | //combineTextClosure = { text1, text2 -> String in 80 | // 81 | // text1 + text2 82 | //} 83 | 84 | // We can even initialize it like this... where all type are inferred and 85 | // Swift allows us to talk about the arguments using place-holder substitutions. 86 | 87 | //combineTextClosure = { 88 | // $0 + $1 89 | //} 90 | 91 | // Finally, test our closure here! 92 | print(combineTextClosure("Text combined by a ", "closure!")) 93 | 94 | //------------------------------------------------------------------------------ 95 | 96 | // Ok, so closures are basically blocks of code that we can pass around like 97 | // variables, but what are closures good for? 98 | 99 | // Most often in iOS development, you'll run into a closure as being the type 100 | // required by a parameter of a function. In this common case, the closure is 101 | // being used as a callback which the function can use to "call back" to the 102 | // programmer. When the function calls back with the closure, the programmer 103 | // will have a chance to execute some code depending on what happened in the 104 | // function. 105 | 106 | // The function below will take a closure and delay the execution of it for 107 | // the number of seconds specified. The parameter name for the closure is 108 | // 'workClosure' and it takes a single string as an argument and returns 109 | // nothing: (String) -> () 110 | 111 | func doSomeDelayedWork(timeToDelay: Double, workToDo: @escaping (String) -> ()) { 112 | 113 | // We'll use a call to DispatchQueue.main.asyncAfter to delay the execution 114 | // of some number of seconds in the future. 115 | 116 | let dispatchTime = DispatchTime.now() + Double(Int64(timeToDelay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC) 117 | 118 | DispatchQueue.main.asyncAfter(deadline: dispatchTime, execute: { 119 | 120 | // Put the code which should be executed with a delay here: 121 | 122 | // Since the parameter 'workClosure' is a closure, we can execute 123 | // it's code by calling the closure like a function. 124 | workToDo("Calling closure delayed for \(timeToDelay) seconds!") 125 | }) 126 | } 127 | 128 | // To test our function that takes a closure, we could create a closure 129 | // that matches the closure type specified by the function above called 130 | // 'doSomeDelayedWork' and then pass it as an argument like so. 131 | 132 | var myWorkToDelay: (String) -> () = { message in 133 | print(message) 134 | } 135 | 136 | doSomeDelayedWork(timeToDelay: 2, workToDo: myWorkToDelay) 137 | 138 | 139 | // Of course, it is more typical to see the closure passed directly into the 140 | // function call instead being assigned to a var first. 141 | doSomeDelayedWork(timeToDelay: 4, workToDo: { message in print(message) }) 142 | 143 | 144 | // Here's how to call the same function using the Trailing Closure syntax. 145 | // Trailing closures are most useful when the code in the closure is too 146 | // complex to write out as a single line of code. 147 | doSomeDelayedWork(timeToDelay: 6) { message in 148 | print(message) 149 | } 150 | 151 | 152 | // Since this sample makes use of some asynchronous code, we will need to tell 153 | // them playground to continue spinning the main run loop, so the asynchronous 154 | // code has a chance to run till completion. 155 | 156 | PlaygroundPage.current.needsIndefiniteExecution = true 157 | -------------------------------------------------------------------------------- /swift_16_closures.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /swift_16_closures.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /swift_17_extensions.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import UIKit 3 | 4 | //------------------------------------------------------------------------------ 5 | 6 | // Extensions add new functionality to an existing class, structure, enumeration, 7 | // or protocol type. This includes the ability to extend types for which you do 8 | // not have access to the original source code (known as retroactive modeling). 9 | 10 | // Extensions in Swift can: 11 | 12 | // Add computed properties and computed type properties 13 | // Define instance methods and type methods 14 | // Provide new initializers 15 | // Define subscripts 16 | // Define and use new nested types 17 | // Make an existing type conform to a protocol 18 | 19 | // This extension allows any Int value to return its square. 20 | 21 | extension Int { 22 | 23 | var squared: Int { 24 | return(self * self) 25 | } 26 | 27 | } 28 | 29 | var myNumber = 3 30 | myNumber.squared 31 | 32 | 3.squared 33 | 34 | //------------------------------------------------------------------------------ 35 | 36 | var hello: String = "Hello, world!" 37 | 38 | print(hello.contains("world")) 39 | 40 | // This extension allows any String value to return whether or not it is a 41 | // holding a value that might be a Gmail email address. 42 | 43 | extension String { 44 | 45 | var isGmailAccount: Bool { 46 | return self.contains("@gmail.com") 47 | } 48 | 49 | } 50 | 51 | var someEmailAddress: String = "jennifer@yahoo.com" 52 | 53 | print(someEmailAddress.isGmailAccount) 54 | 55 | var anotherEmailAddress: String = "rob@gmail.com" 56 | 57 | print(anotherEmailAddress.isGmailAccount) 58 | -------------------------------------------------------------------------------- /swift_17_extensions.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /swift_17_extensions.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /swift_18_error_handling.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | //------------------------------------------------------------------------------ 3 | 4 | // Error Handling 5 | 6 | // Error handling is the process of responding to and recovering from error 7 | // conditions in your program. 8 | 9 | // https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ErrorHandling.html#//apple_ref/doc/uid/TP40014097-CH42-ID508 10 | 11 | //------------------------------------------------------------------------------ 12 | 13 | // In Swift, errors are represented by values that conform to the ErrorType 14 | // protocol and are typically implemented using enumerations which allow us to 15 | // group several related error conditions together. Using enumerations also 16 | // allows us to set associated values which can be used to pass additional 17 | // information about the nature of an error. 18 | // 19 | // For example, here’s how you might represent the error conditions of operating 20 | // a vending machine. 21 | 22 | enum VendingMachineError: Error { 23 | 24 | case InvalidSelection 25 | case OutOfStock 26 | case InsufficientFunds(coinsNeeded: Int) 27 | } 28 | 29 | // Next, we'll create a VendingMachine class that uses the VendingMachineError 30 | // to communicate error conditions back to the users of the class. 31 | 32 | struct Item { 33 | 34 | var price: Int 35 | var count: Int 36 | } 37 | 38 | class VendingMachine { 39 | 40 | var inventory = [ 41 | "Candy Bar": Item(price: 12, count: 7), 42 | "Chips": Item(price: 10, count: 4), 43 | "Pretzels": Item(price: 7, count: 11) 44 | ] 45 | 46 | var coinsDeposited = 0 47 | 48 | func dispenseSnack(snack: String) { 49 | print("Dispensing \(snack)") 50 | } 51 | 52 | func vend(itemNamed name: String) throws { 53 | 54 | guard let item = inventory[name] else { 55 | throw VendingMachineError.InvalidSelection 56 | } 57 | 58 | guard item.count > 0 else { 59 | throw VendingMachineError.OutOfStock 60 | } 61 | 62 | guard item.price <= coinsDeposited else { 63 | throw VendingMachineError.InsufficientFunds(coinsNeeded: item.price - coinsDeposited) 64 | } 65 | 66 | coinsDeposited -= item.price 67 | 68 | var newItem = item 69 | newItem.count -= 1 70 | inventory[name] = newItem 71 | 72 | dispenseSnack(snack: name) 73 | } 74 | } 75 | 76 | //------------------------------------------------------------------------------ 77 | 78 | // Now, lets test our VendingMachine class: 79 | 80 | var vendingMachine = VendingMachine() 81 | 82 | vendingMachine.coinsDeposited = 8 83 | 84 | // The first thing you'll notice is that you can't simply call the vend() method 85 | // without writing extra code to catch the errors that may result from calling 86 | // vend(). 87 | 88 | // This will not work! 89 | //vendingMachine.vend(itemNamed:"Chips") 90 | 91 | do { 92 | 93 | try vendingMachine.vend(itemNamed: "Chips") 94 | 95 | } catch VendingMachineError.InvalidSelection { 96 | 97 | print("Invalid Selection.") 98 | 99 | } catch VendingMachineError.OutOfStock { 100 | 101 | print("Out of Stock.") 102 | 103 | } catch VendingMachineError.InsufficientFunds(let coinsNeeded) { 104 | 105 | print("Insufficient funds. Please insert an additional \(coinsNeeded) coins.") 106 | } 107 | 108 | 109 | //------------------------------------------------------------------------------ 110 | 111 | // But, if the vend() method is being called inside another function or method, 112 | // we can pass responsibility for catching and handling the errors to someone 113 | // else by having the function or method throw the errors to the caller for 114 | // handling. 115 | 116 | 117 | let favoriteSnacks = [ 118 | 119 | "Alice": "Chips", 120 | "Bob": "Licorice", 121 | "Eve": "Pretzels", 122 | ] 123 | 124 | func buyFavoriteSnack(person: String, vendingMachine: VendingMachine) throws { 125 | 126 | // Get the person's favorite snack. If nil - just default to "Candy Bar". 127 | let snackName = favoriteSnacks[person] ?? "Candy Bar" 128 | 129 | // Try to vend the snack, but if an error occurs, throw it to the caller 130 | // of this function for handling. 131 | try vendingMachine.vend(itemNamed: snackName) 132 | } 133 | 134 | 135 | var vendingMachine2 = VendingMachine() 136 | 137 | vendingMachine2.coinsDeposited = 4 138 | 139 | 140 | do { 141 | 142 | try buyFavoriteSnack(person: "Eve", vendingMachine: vendingMachine2) 143 | 144 | } catch VendingMachineError.InvalidSelection { 145 | 146 | print("Invalid Selection.") 147 | 148 | } catch VendingMachineError.OutOfStock { 149 | 150 | print("Out of Stock.") 151 | 152 | } catch VendingMachineError.InsufficientFunds(let coinsNeeded) { 153 | 154 | print("Insufficient funds. Please insert an additional \(coinsNeeded) coins.") 155 | } 156 | 157 | //------------------------------------------------------------------------------ 158 | 159 | // Disabling Error Propagation 160 | 161 | // Sometimes you know a throwing function or method won’t, in fact, throw an 162 | // error at runtime. On those occasions, you can write "try!" before the expression 163 | // to disable error propagation and wrap the call in a runtime assertion that no 164 | // error will be thrown. If an error actually is thrown, you’ll get a runtime error. 165 | 166 | var vendingMachine3 = VendingMachine() 167 | 168 | vendingMachine3.coinsDeposited = 100 169 | 170 | try! vendingMachine3.vend(itemNamed: "Chips") 171 | 172 | //------------------------------------------------------------------------------ 173 | 174 | // Specifying Cleanup Actions 175 | 176 | // You can use a defer statement to execute some code just before code execution 177 | // leaves the current block of code. This statement lets you do any necessary 178 | // cleanup that should be performed regardless of how execution leaves the 179 | // current block of code — whether it leaves because an error was thrown or 180 | // because of a statement such as return or break. 181 | 182 | // In the example function below, a defer statement is used to ensure that the 183 | // file descriptor is guaranteed to be closed once we leave the scope of the 184 | // if statement "if exists(filename)" 185 | 186 | /* 187 | 188 | func processFile(filename: String) throws { 189 | 190 | if exists(filename) { 191 | 192 | let file = open(filename) 193 | 194 | defer { 195 | close(file) 196 | } 197 | 198 | while let line = try file.readline() { 199 | // Work with the file. 200 | } 201 | 202 | // Our defer code will be called here, at the end of the scope and 203 | // will guarantee that close(file) will get called. 204 | } 205 | } 206 | 207 | */ 208 | -------------------------------------------------------------------------------- /swift_18_error_handling.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /swift_18_error_handling.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /swift_1_variables.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import UIKit 3 | 4 | // This one line is a comment! 5 | 6 | /* 7 | This is a comment that can span 8 | over multiple lines! 9 | */ 10 | 11 | // Use the var keyword to declare a variable. 12 | 13 | var myScore = 0 14 | 15 | // Use the let keyword to declare a constant. A constant holds a value 16 | // just like a variable but it can never be changed once it has been 17 | // assigned a value. 18 | 19 | let maxGoldCoins = 500 20 | 21 | // You can declare multiple constants or multiple variables on a single line 22 | // if you separate them by commas: 23 | 24 | var health = 100, armor = 25, goldCoins = 10, rubies = 5 25 | 26 | //------------------------------------------------------------------------------ 27 | 28 | // Variable and constant names can contain almost any character, including 29 | // Unicode characters such as the symbol for Pi or emojis. 30 | let π = 3.14159 31 | let my🐶name = "Spot" 32 | 33 | // To insert an emoji use: Command + Ctrl + Spacebar 34 | // In most cases, you should really avoid this! 35 | 36 | // One of the possible valid uses of this would be for programmers to write 37 | // their code in their own native language. 38 | let 你好 = "你好世界" 39 | 40 | //------------------------------------------------------------------------------ 41 | 42 | // Swift gives us several built-in functions which we are designed to help us out. 43 | // For example, we can use the print() function to print our data to the console. 44 | 45 | var shopKeeperText = "Would you like to buy something for your adventure?" 46 | 47 | print(shopKeeperText) 48 | 49 | shopKeeperText = "How about a sword or a new suit of armor?" 50 | 51 | print(shopKeeperText) 52 | 53 | //------------------------------------------------------------------------------ 54 | 55 | // If we want to build-up a String using some of our variables, we can use 56 | // string interpolation to include the name of a constant or variable 57 | // into another string. 58 | 59 | // To do this, wrap the var name in parentheses and escape it with a backslash 60 | // before the opening parenthesis. 61 | // 62 | // Like this: \(varName) 63 | 64 | var weapon = "Dagger" 65 | var price = 2 66 | 67 | print("Are you sure you want to purchase the \(weapon) for \(price) gold coins?") 68 | 69 | weapon = "Short Sword" 70 | price = 10 71 | 72 | print("Are you sure you want to purchase the '\(weapon)' for \(price) gold coins?") 73 | 74 | weapon = "Mystical Blade of Awesomeness" 75 | price = 1000 76 | 77 | print("Are you sure you want to purchase the \"\(weapon)\" for \(price) gold coins?") 78 | 79 | -------------------------------------------------------------------------------- /swift_1_variables.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /swift_1_variables.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /swift_1_variables.playground/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /swift_2_basic_types.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import UIKit 3 | 4 | // Swift is a type-safe language. This means that we need to tell Swift what 5 | // types our variables or constants are supposed to be. This way, if part of 6 | // our code expects a String, we can’t pass it an Int by mistake. 7 | 8 | // To make things easy on us, Swift uses Type Inference to figure out or 9 | // 'infer' what type a variable or constant is meant to be. 10 | 11 | // This is obviously a String since we assigned it a string of characters. 12 | let gameTitle = "Angry Birds" 13 | 14 | // And this is an Int since we assigned it a whole number with no fractional part. 15 | var score = 1500 16 | 17 | // You can check the type of a variable by passing it into a function called 18 | // type(of:) 19 | print( "gameTitle is of type: \(type(of: gameTitle))") 20 | print( "score is of type: \(type(of: score))") 21 | 22 | //------------------------------------------------------------------------------ 23 | 24 | // If we don't have an initial value that will specify the type, we can use a 25 | // Type Annotation to specify what it is until we assign a value to it. 26 | 27 | var playersName: String 28 | var playersScore: Int 29 | 30 | //------------------------------------------------------------------------------ 31 | 32 | // If we want to work with numbers that have a fractional component such as 33 | // 3.1415926 we can use two other types called Float and Double. 34 | 35 | let PI = 3.1415926 36 | 37 | print( "PI is of type: \(type(of: PI))") 38 | 39 | // The reason we get two types, Float and Double, for fractional numbers is 40 | // because we get to choose how much accuracy we want. A Float takes up less 41 | // memory than a Double but it is less accurate. 42 | 43 | // For example, if we use a Double for our var latitude, and the fractional 44 | // part has a lot of numbers, everything will still be fine. 45 | var latitude: Double 46 | latitude = 36.166667 47 | 48 | // But notice how our longitude, which is using a Float, loses the last 3 49 | // from its value's end. Does it matter? Well, that depends on what you're 50 | // going to do with the value. 51 | var longitude: Float 52 | longitude = -86.783333 53 | 54 | //------------------------------------------------------------------------------ 55 | 56 | // Another built-in data type of Swift is called Bool, which is short for Boolean. 57 | // Bools can only store the values true or false. 58 | 59 | var playerFoundMagicKey: Bool 60 | 61 | playerFoundMagicKey = true 62 | 63 | //------------------------------------------------------------------------------ 64 | 65 | // There's also a type called Character which can only hold a single character value. 66 | // It's often used when processing or manipulating String data. 67 | var aSingleLetter: Character 68 | 69 | aSingleLetter = "A" 70 | 71 | //------------------------------------------------------------------------------ 72 | 73 | // There are other specialty types such Int64 and Uint, but these are typically 74 | // only used in cases where a function or method requires their use. 75 | 76 | // Here's a listing of some of these specialty types: 77 | 78 | // Int16 - A 16-bit signed integer value type. 79 | // Int32 - A 32-bit signed integer value type. 80 | // Int64 - A 64-bit signed integer value type. 81 | // Int8 - An 8-bit signed integer value type. 82 | // UInt - A 64-bit unsigned integer value type. 83 | // UInt16 - A 16-bit unsigned integer value type. 84 | // UInt32 - A 32-bit unsigned integer value type. 85 | // UInt64 - A 64-bit unsigned integer value type. 86 | // UInt8 - An 8-bit unsigned integer value type. 87 | // UTF16 - A codec for UTF-16. 88 | // UTF32 - A codec for UTF-32. 89 | // UTF8 - A codec for UTF-8. 90 | 91 | // You can see this and others listed under the docs for the The Swift Standard Library: 92 | 93 | // https://developer.apple.com/library/tvos/documentation/General/Reference/SwiftStandardLibraryReference/index.html 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /swift_2_basic_types.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /swift_2_basic_types.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /swift_3_operators.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import UIKit 3 | 4 | 5 | // Arithmetic Operators 6 | 7 | // We've already seen the assignment operator (=) in action: 8 | 9 | var myVar = 42 10 | 11 | // In addition to assignment, Swift supports the four standard arithmetic 12 | // operators for all number types: 13 | // Addition (+) 14 | // Subtraction (-) 15 | // Multiplication (*) 16 | // Division (/) 17 | 18 | var testVar1 = 1 + 2 // Equals 3 19 | var testVar2 = 5 - 3 // Equals 2 20 | var testVar3 = 2 * 3 // Equals 6 21 | var testVar4 = 10.0 / 2.5 // Equals 4.0 22 | 23 | //------------------------------------------------------------------------------ 24 | 25 | // Compound Assignment Operators 26 | 27 | // Like C, Swift provides compound assignment operators that combine assignment 28 | // (=) with another operation. We can use these special assignment operators 29 | // to reduce the amount of code we have to write. 30 | 31 | var myNumber = 100 32 | 33 | myNumber += 5 // Same as saying: myNumber = myNumber + 5 34 | 35 | myNumber -= 5 // Same as saying: myNumber = myNumber - 5 36 | 37 | myNumber *= 5 // Same as saying: myNumber = myNumber * 5 38 | 39 | myNumber /= 5 // Same as saying: myNumber = myNumber / 5 40 | 41 | //------------------------------------------------------------------------------ 42 | 43 | // The addition operator is also supported for Strings. When the addition 44 | // operator is used to join two Strings together it is called, concatenation. 45 | 46 | print("Hello, " + "world!") // Equals the single String, "Hello, world". 47 | 48 | //------------------------------------------------------------------------------ 49 | 50 | // Comparison Operators 51 | 52 | // Swift supports all standard C comparison operators: 53 | 54 | // Equal to (a == b) 55 | // Not equal to (a != b) 56 | // Greater than (a > b) 57 | // Less than (a < b) 58 | // Greater than or equal to (a >= b) 59 | // Less than or equal to (a <= b) 60 | 61 | 1 == 1 // true, because 1 is equal to 1 62 | 2 != 1 // true, because 2 is not equal to 1 63 | 2 > 1 // true, because 2 is greater than 1 64 | 1 < 2 // true, because 1 is less than 2 65 | 1 >= 1 // true, because 1 is greater than or equal to 1 66 | 2 <= 1 // false, because 2 is not less than or equal to 1 67 | 68 | //------------------------------------------------------------------------------ 69 | 70 | // Logical Operators 71 | 72 | // Logical operators modify or combine the Boolean logic values true and false. 73 | // Swift supports the three standard logical operators found in C-based languages: 74 | // 75 | // Logical AND (a && b) - Returns true if both expressions are true 76 | // Logical OR (a || b) - Returns true if either of the two expressions are true 77 | // Logical NOT (!a) - Negates or inverts the expression's result. 78 | 79 | 2 > 1 && 4 > 2 // true, because both 2 > 1 AND 4 > 2 are true. 80 | 81 | 2 > 1 || 0 > 100 // true, because at least one of the expressions is true. 82 | 83 | !(1 == 1) // false because 1 is equal to 1 but the ! inverts the result 84 | // and makes it false. 85 | 86 | //------------------------------------------------------------------------------ 87 | 88 | // The Remainder Operator 89 | 90 | // The remainder operator (a % b) works out how many multiples of b will fit 91 | // inside a and returns the value that is left over (known as the remainder). 92 | 93 | // For example, if we divide 9 by 4 we get 2 since at least two 4's can fit into 9 94 | // but what about the remainder? 95 | var quotient = 9 / 4 96 | 97 | print("How many 4's can fit into 9: \(quotient)") 98 | 99 | // If we want to know just about the remainder we can use the '%' or the remainder 100 | // operator to find out what the remainder is after the 9 is divided by 4. 101 | var remainder = 9 % 4 102 | 103 | print("The remainder of dividing 9 by 4 is: \(remainder)") 104 | 105 | // While the remainder operator is not used very often in day-to-day coding, it 106 | // often pops in interview questions where you will be asked to identify numbers 107 | // that are the "multiples of some other number", or "divisible by some other number". 108 | 109 | // For example, if you're asked to identity all the numbers that are "multiples of three" 110 | // then you could use the remainder operator to find the like so: 111 | 112 | 15 % 3 == 0 // Is 15 a multiple of 3? 113 | 114 | 10 % 3 == 0 // Is 10 a multiple of 3? 115 | 116 | //------------------------------------------------------------------------------ 117 | 118 | // Ternary Conditional Operator 119 | 120 | // The ternary conditional operator is a special operator with three parts, which 121 | // takes the form of question ? answer1 : answer2. 122 | 123 | var speed = 100 124 | var turboButtonPressed = true 125 | 126 | speed = (turboButtonPressed ? speed * 2 : speed) 127 | 128 | // With out a Ternary Conditional Operator, we would have to write a bit more 129 | // code to get the same result. 130 | 131 | speed = 100 132 | turboButtonPressed = true 133 | 134 | if turboButtonPressed { 135 | speed = speed * 2 136 | } 137 | 138 | -------------------------------------------------------------------------------- /swift_3_operators.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /swift_3_operators.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /swift_4_collection_types.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import UIKit 3 | 4 | // Swift provides three primary collection types, known as arrays, dictionaries, 5 | // and sets, for storing collections of values. 6 | 7 | // Arrays are ordered collections of values. 8 | // Dictionaries are unordered collections of key-value pairs or associations. 9 | // Sets are unordered collections of unique values. 10 | 11 | //------------------------------------------------------------------------------ 12 | 13 | // This is how to create an empty array that is ready to hold Strings. 14 | 15 | var emptyArray = [String]() 16 | 17 | // This creates an array to hold some weapon names for a game! 18 | // Since we added some values to it during the creation, Swift knows it holds 19 | // Strings so we don't need to specify that. 20 | 21 | var weaponsList = ["Dagger", "Sword", "Club"] 22 | 23 | // Since the order of our array entries are maintained, we can index into the 24 | // array using a number. 25 | 26 | print(weaponsList[0]) 27 | print(weaponsList[1]) 28 | print(weaponsList[2]) 29 | 30 | // We can also just ask for the whole array to be printed out. 31 | 32 | print(weaponsList) 33 | 34 | // Be careful though! Indexing an array position that doesn't exist can cause a crash! 35 | // print(weaponsList[3]) 36 | 37 | // We can also use the subscript syntax to assign a new value to the var being stored 38 | // there. 39 | 40 | weaponsList[2] = "Battle Mace" // Upgrade that old Club to a Battle Mace! 41 | 42 | print(weaponsList[2]) 43 | 44 | // We can add new entries to the array by calling the append method. The append 45 | // method always adds to the end of the array. 46 | weaponsList.append("Long Bow") 47 | 48 | print(weaponsList) 49 | 50 | // If we want to add something at a certain index, we can use a special version 51 | // of insert to insert a new value at that index. 52 | weaponsList.insert("Broad Sword", at: 2) 53 | 54 | print(weaponsList) 55 | 56 | // Likewise, we can also remove items with calls like removeAtIndex, removeFirst, 57 | // or removeLast 58 | weaponsList.remove(at: 1) 59 | 60 | print(weaponsList) 61 | 62 | // You can wipe out an existing array and replace it with an empty one by 63 | // assigning it to []. 64 | 65 | weaponsList = [] 66 | 67 | //------------------------------------------------------------------------------ 68 | 69 | // This is how to create an empty dictionary that can hold key value pairs where 70 | // the key is of type String and the value is of type Float. 71 | 72 | var emptyDictionary = [String : Float]() 73 | 74 | // This creates a dictionary of player names and their scores. The player's name 75 | // is the key of type String, which points to the score which is the value of 76 | // type Int. 77 | 78 | var playerScores = [ 79 | "Calvin": 2100, 80 | "Jennifer": 2700, 81 | ] 82 | 83 | // We can access the individual values stored in the dictionary by using the keys. 84 | 85 | print(playerScores["Calvin"]) 86 | print(playerScores["Jennifer"]) 87 | 88 | // We can also just ask for the whole dictionary to be printed out. 89 | 90 | print(playerScores) 91 | 92 | // We can use the subscript syntax to add a new key-value pairs to 93 | // the dictionary. 94 | 95 | playerScores["Kim"] = 3300 96 | 97 | print(playerScores) 98 | 99 | // We can also use subscript syntax to change the value associated with an 100 | // existing key. 101 | playerScores["Calvin"] = 3000 102 | 103 | // You can wipe out an existing dictionary and replace it with an empty one by 104 | // assigning it to [:]. 105 | 106 | playerScores = [:] 107 | 108 | //------------------------------------------------------------------------------ 109 | 110 | // A Set stores distinct values of the same type in a collection with no defined 111 | // ordering. You can use a Set instead of an Array when the order of items is not 112 | // important, or when you need to ensure that a value only appears once in the 113 | // collection. 114 | 115 | var letters = Set() 116 | 117 | print("Our set has \(letters.count) items.") 118 | 119 | letters.insert("A") 120 | 121 | print("Our set has \(letters.count) items.") 122 | 123 | letters.insert("A") // Our set already has an "A", so this will do nothing. 124 | 125 | print("Our set has \(letters.count) items.") 126 | 127 | letters.insert("B") 128 | 129 | print("Our set has \(letters.count) items.") 130 | 131 | -------------------------------------------------------------------------------- /swift_4_collection_types.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /swift_4_collection_types.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /swift_5_conditional_logic.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import UIKit 3 | 4 | // We can use if-statements to have our code take some action if some 5 | // condition is true. The most basic control structure is the if-statement. 6 | 7 | var health = 0 8 | 9 | // If the player's health is less than or equal to 0 - print "You're dead!" 10 | if health <= 0 { 11 | print( "You're dead!" ) 12 | } 13 | 14 | //------------------------------------------------------------------------------ 15 | 16 | // Next, the if-else statement allows us to pick one of two possible actions instead 17 | // of a all-or-nothing choice. 18 | 19 | health = 75 20 | 21 | // If the player's health is less than or equal to 0 - print "You're dead!" 22 | // Otherwise, print "You're alive!". 23 | if health <= 0 { 24 | print( "You're dead!" ) 25 | } else { 26 | print( "You're alive!" ) 27 | } 28 | 29 | //------------------------------------------------------------------------------ 30 | 31 | // The final form of an if-statement, uses an else-if combination to pick from 32 | // one of several possible actions by chaining two or more if statements 33 | // together. 34 | 35 | health = 24 36 | 37 | // If the player's health is less than or equal to 0 - print "You're dead!" 38 | // But if the player is not dead, and the player's health is less than 25 - 39 | // print "You're alive - but badly wounded!" Otherwise, print "You're alive!". 40 | if health <= 0 { 41 | print( "You're dead!" ) 42 | } else if health < 25 { 43 | print( "You're alive - but badly wounded!" ) 44 | } else { 45 | print( "You're alive!" ) 46 | } 47 | 48 | //------------------------------------------------------------------------------ 49 | 50 | // If we want to write if-statements that check multiple expressions we can 51 | // use Logical Operators to decided if an if-statement should be executed 52 | // or not. 53 | 54 | // Swift Logical Operators 55 | 56 | // Logical AND (a && b) - Returns true if both expressions are true 57 | // Logical OR (a || b) - Returns true if either of the two expressions are true 58 | // Logical NOT (!a) - Negates or inverts the expression's result. 59 | 60 | let goldCoins = 800 61 | let rubies = 5 62 | 63 | let priceUsingGold = 500 64 | let priceUsingRubies = 10 65 | 66 | var hasSword = true // Does the shop keeper have one to sell? 67 | 68 | // If the player has enough gold coins AND the shop keeper has a magic sword 69 | // to sell - ask the player if he would like to purchase it. 70 | 71 | if goldCoins >= priceUsingGold && hasSword == true { 72 | print("Would you like to purchase a magic sword?") 73 | } else { 74 | print("I'm sorry. The magic sword is unavailable.") 75 | } 76 | 77 | // If the player has enough gold coins OR the player has enough ruby gems - 78 | // ask the player if he would like to purchase it. 79 | 80 | if goldCoins >= priceUsingGold || rubies >= priceUsingRubies { 81 | print("Would you like to purchase a magic sword?") 82 | } else { 83 | print("I'm sorry. The magic sword is unavailable.") 84 | } 85 | 86 | // The 'not' Logical Operator just inverts or negates a Boolean variable or the 87 | // result of an expression. 88 | 89 | hasSword = false 90 | 91 | if !hasSword { 92 | print("The shop keeper has no magic sword!") 93 | } 94 | 95 | //------------------------------------------------------------------------------ 96 | 97 | // A switch statement provides an alternative to the if statement when we need 98 | // to compare a value against several possible matches. 99 | 100 | var someCharacter: Character = "e" 101 | 102 | //someCharacter = "k" 103 | //someCharacter = "U" 104 | //someCharacter = "X" 105 | //someCharacter = "🐶" 106 | 107 | switch someCharacter { 108 | 109 | case "a", "e", "i", "o", "u": 110 | print("\(someCharacter) is a lower-case vowel.") 111 | 112 | case "A", "E", "I", "O", "U": 113 | print("\(someCharacter) is a upper-case vowel.") 114 | 115 | case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m", 116 | "n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z": 117 | print("\(someCharacter) is a lower-case consonant.") 118 | 119 | case "B", "C", "D", "F", "G", "H", "J", "K", "L", "M", 120 | "N", "P", "Q", "R", "S", "T", "V", "W", "X", "Y", "Z": 121 | print("\(someCharacter) is a upper-case consonant.") 122 | 123 | default: 124 | print("\(someCharacter) is not a vowel or a consonant!") 125 | } 126 | 127 | //------------------------------------------------------------------------------ 128 | 129 | // For numbers, we can use Interval Matching to see if our value is included in 130 | // an interval. This example uses number intervals to build up a sentence based 131 | // on the number of gold coins a player has: 132 | 133 | var playersGold = 250 134 | 135 | var generalAmount: String 136 | 137 | switch playersGold { 138 | 139 | case 0: 140 | generalAmount = "no" 141 | 142 | case 1...5: 143 | generalAmount = "only a few" 144 | 145 | case 5...100: 146 | generalAmount = "some" 147 | 148 | case 100...1000: 149 | generalAmount = "hundreds of" 150 | 151 | default: 152 | generalAmount = "a considerable amount of" 153 | } 154 | 155 | let shopKeeperText = "I see that you have \(generalAmount) gold coins." 156 | 157 | print(shopKeeperText) 158 | 159 | 160 | -------------------------------------------------------------------------------- /swift_5_conditional_logic.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /swift_5_conditional_logic.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /swift_6_looping.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import UIKit 3 | 4 | // For-In looping 5 | 6 | // You can use the for-in loop to iterate over a sequence, such as ranges of 7 | // numbers, items in an array, or characters in a string. 8 | 9 | // This example uses a range of numbers to print out a test message 4 times. 10 | 11 | for index in 0...3 { 12 | print("Current index in range is: \(index)") 13 | } 14 | 15 | // This for-in loop also uses a range of numbers to print out a test message, 16 | // but calls reverse on it to print the index values in reverse order. 17 | for index in (0...3).reversed() { 18 | print("Current index reversed range is: \(index)") 19 | } 20 | 21 | //------------------------------------------------------------------------------ 22 | 23 | // This example iterates over an array of player weapons. 24 | 25 | var weaponsList = ["Dagger", "Sword", "Club"] 26 | 27 | for weapon in weaponsList { 28 | print("Player has a \(weapon)!") 29 | } 30 | 31 | //------------------------------------------------------------------------------ 32 | 33 | // This example iterates over an dictionary of player's names and scores. 34 | 35 | var playerScores = [ 36 | "Calvin": 2100, 37 | "Jennifer": 2700, 38 | "Debbie": 3000, 39 | ] 40 | 41 | for (name, score) in playerScores { 42 | print("\(name) scored \(score) points.") 43 | } 44 | 45 | //------------------------------------------------------------------------------ 46 | 47 | // If a String is passed to a For-In loop, it will be treated as a character 48 | // collection which can be iterated through character by character. 49 | 50 | var myString = "LOL" 51 | 52 | for character in myString { 53 | print(character) 54 | } 55 | 56 | //------------------------------------------------------------------------------ 57 | 58 | // If you don't need the index variable, you can ignore the values by using an 59 | // underscore in place of a variable name. 60 | 61 | for _ in 1...3 { 62 | print("Bang!") 63 | } 64 | 65 | //------------------------------------------------------------------------------ 66 | 67 | // We can use the stride method to create a sequence of numbers that can 68 | // increment a for loop by some value other than 1. 69 | 70 | for index in stride(from: 0, to: 10, by: 2) { 71 | print("Stride index: \(index)") 72 | } 73 | 74 | //------------------------------------------------------------------------------ 75 | 76 | // The while loop continues looping while the expression is true. 77 | 78 | let numRocketsToFire = 3 79 | var rocketCount = 0 80 | 81 | while rocketCount < numRocketsToFire { 82 | 83 | rocketCount += 1 84 | 85 | print( "Firing rocket #\(rocketCount)" ) 86 | } 87 | 88 | //------------------------------------------------------------------------------ 89 | 90 | // We can use the 'break' keyword to break out of a while loop early if we find 91 | // a reason to. 92 | 93 | var answer = 0 94 | 95 | while answer < 100 { 96 | 97 | print("Testing answer \(answer)") 98 | 99 | if answer == 42 { 100 | 101 | // If the number is 42 - stop looping and jump out of the loop's body! 102 | print("We just found it... The Answer to the Ultimate Question of Life, the Universe, and Everything!") 103 | break 104 | } 105 | 106 | answer += 1 107 | } 108 | 109 | //------------------------------------------------------------------------------ 110 | 111 | // The 'continue' keyword allows us to skip the rest of the loop's body and jump 112 | // to the loop's top. 113 | 114 | answer = 0 115 | 116 | while answer < 50 { 117 | 118 | answer += 1 119 | 120 | print("Testing answer \(answer)") 121 | 122 | if answer != 42 { 123 | 124 | // If the answer is not equal to 42 - keep looping, but jump straight 125 | // back to the top! 126 | continue 127 | } 128 | 129 | print("We just found it... The Answer to the Ultimate Question of Life, the Universe, and Everything!") 130 | break 131 | } 132 | 133 | //------------------------------------------------------------------------------ 134 | 135 | // Repeat-While 136 | 137 | // The other variation of the while loop, known as the repeat-while loop, 138 | // performs a single pass through the loop block first, before considering the 139 | // loop's condition. It then continues to repeat the loop until the condition 140 | // is false. 141 | 142 | var number = 0 143 | 144 | repeat { 145 | 146 | print( "Repeating \(number)" ) 147 | 148 | number += 1 149 | 150 | } while number < 3 151 | 152 | 153 | 154 | -------------------------------------------------------------------------------- /swift_6_looping.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /swift_6_looping.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /swift_7_functions.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import UIKit 3 | 4 | 5 | // Functions are self-contained chunks of code that perform a specific task. 6 | // You give a function a name that identifies what it does, and this name 7 | // is used to “call” the function to perform its task when needed. 8 | 9 | // Here is a simple function called "sayGameOver". It takes no arguments and 10 | // returns no value. It simply prints "Game Over!". 11 | 12 | func sayGameOver() { 13 | 14 | print("Game Over!") 15 | } 16 | 17 | sayGameOver() 18 | 19 | //------------------------------------------------------------------------------ 20 | 21 | // A function can be more useful if we pass it additional information via 22 | // parameters. 23 | 24 | // By adding a new parameter called "playersName" which is of type String, this 25 | // function can now print a customized game over message that includes the 26 | // player's name. 27 | 28 | func sayGameOver2(playersName: String) { 29 | 30 | print("Game Over, \(playersName)!") 31 | } 32 | 33 | // Here we call our new function and pass it an argument value of "Robert". 34 | // If the value of the passed argument matches the parameter's type, the value 35 | // will be passed into the function and be accessible using the parameter's name 36 | // which is called "playersName" 37 | 38 | sayGameOver2(playersName: "Robert") 39 | 40 | //------------------------------------------------------------------------------ 41 | 42 | // Functions can also do work and return the result of that work as a return 43 | // value. 44 | 45 | // This version of our function does not print a message but returns is as a 46 | // String, which other code can use. 47 | 48 | func sayGameOver3(playersName: String) -> String { 49 | 50 | let text = "Game Over, \(playersName)!" 51 | 52 | return text 53 | } 54 | 55 | // Here we call our function and then catch the return value in our var called 56 | // gameOverMessage. 57 | 58 | var gameOverMessage = sayGameOver3(playersName: "Robert") 59 | 60 | print(gameOverMessage) 61 | 62 | gameOverMessage = sayGameOver3(playersName: "Jennifer") 63 | 64 | print(gameOverMessage) 65 | 66 | //------------------------------------------------------------------------------ 67 | 68 | // Functions can have more than one argument. This function takes two arguments: 69 | // one that is a String for the player's name and a second one that is an Int 70 | // which represents the player's score. 71 | 72 | func sayGameOver4(playersName: String, playersScore: Int) -> String { 73 | 74 | let text = "Game Over, \(playersName)! Your final score is \(playersScore)" 75 | 76 | return text 77 | } 78 | 79 | // To call this function, we can pass just a String for playersScore, but for 80 | // the second argument, we must specify the parameter's name when we pass the 81 | // value. 82 | 83 | print( sayGameOver4(playersName: "Kim", playersScore: 2500) ) 84 | print( sayGameOver4(playersName: "Charles", playersScore: 2000) ) 85 | 86 | 87 | //------------------------------------------------------------------------------ 88 | 89 | // If we want to, we can specify special external parameter names which are only 90 | // used when calling the function. 91 | 92 | // You write an external parameter name before the internal parameter name it 93 | // supports, separated by a space. 94 | 95 | // The function below specifies both external and internal parameter names for 96 | // both of its arguments. 97 | 98 | func sayGameOver5(playersName name: String, playersScore score: Int) -> String { 99 | 100 | // The internal names must be used inside the function. 101 | let text = "Game Over, \(name)! Your final score is \(score)" 102 | 103 | return text 104 | } 105 | 106 | // The external parameter names must be used when calling the function. 107 | 108 | print( sayGameOver5(playersName: "Rick", playersScore: 1900) ) 109 | print( sayGameOver5(playersName: "Debbie", playersScore: 3000) ) 110 | 111 | 112 | //------------------------------------------------------------------------------ 113 | 114 | // Omitting Parameter Names 115 | 116 | // If you do not want to use parameter names when calling the function, replace 117 | // the external parameter names with an underscore (_) instead. 118 | 119 | func sayGameOver6(_ name: String, _ score: Int) -> String { 120 | 121 | let text = "Game Over, \(name)! Your final score is \(score)" 122 | 123 | return text 124 | } 125 | 126 | // Now, we can call the function with out having to specify any parameter names. 127 | 128 | print( sayGameOver6("Kim", 2500) ) 129 | print( sayGameOver6("Charles", 2000) ) 130 | 131 | //------------------------------------------------------------------------------ 132 | 133 | // Default Values 134 | 135 | // You can define a default argument value for any parameter in a function 136 | // by assigning a value to the parameter after that parameter's type. 137 | // If a default value is defined, you can omit passing an argument for that 138 | // parameter when calling the function. 139 | 140 | func someFunction(someValue: Int = 42) { 141 | 142 | print(someValue) 143 | } 144 | 145 | someFunction(someValue: 6) 146 | someFunction() 147 | 148 | -------------------------------------------------------------------------------- /swift_7_functions.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /swift_7_functions.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /swift_8_functions_advanced.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import UIKit 3 | 4 | 5 | // Functions with Multiple Return Values 6 | 7 | // You can use a tuple type as the return type for a function to return multiple 8 | // values as part of one compound return value. 9 | 10 | func getTheHighScore() -> (name: String, score: Int) { 11 | 12 | // Pretned that we went out to our game server and brought back this data! 13 | let theName = "Chris" 14 | let theScore = 75200 15 | 16 | return (theName, theScore) 17 | } 18 | 19 | let highScoreData = getTheHighScore() 20 | 21 | print("The high score is \(highScoreData.score) held by \(highScoreData.name)") 22 | 23 | 24 | //------------------------------------------------------------------------------ 25 | 26 | // We can also use the keyword "typealias" to name tuple types. We can then use 27 | // these name as a return type for our own functions. 28 | 29 | typealias HighScore = (name: String, score: Int) 30 | 31 | func getTheHighScore2() -> HighScore { 32 | 33 | // Pretend that we went out to our game server and brought back this data! 34 | let theName = "Jennifer" 35 | let theScore = 89500 36 | 37 | return (theName, theScore) 38 | } 39 | 40 | let highScoreData2: HighScore = getTheHighScore2() 41 | 42 | print("The high score is \(highScoreData2.score) held by \(highScoreData2.name)") 43 | 44 | 45 | //------------------------------------------------------------------------------ 46 | 47 | // In-Out Parameters 48 | 49 | // By default, parameters are constants and their values can not be changed. 50 | // For example, the following function will not compile under Swift because it 51 | // is attempting to change the parameter called someNumber. 52 | 53 | //func doSomethingNaughty(someNumber: Int) { 54 | // someNumber = 42 // Forbidden! 55 | //} 56 | 57 | // But there are times when we want the ability to change the values held by 58 | // the variables that were passed into the function. To support this we mark 59 | // the parameters that can be changed as inout parameters. 60 | 61 | func swapTwoInts(_ a: inout Int, _ b: inout Int) { 62 | 63 | let temp = a // Let 'temp' hold the value of 'a'. 64 | a = b // Set 'a' to whatever 'b' is. 65 | b = temp // Finally, set 'b' to what 'a' was. 66 | } 67 | 68 | var var1 = 42 69 | var var2 = 1000 70 | 71 | print("var1 = \(var1), var2 = \(var2)") // Before Swap 72 | 73 | // To pass an argument that can be changed inside the function, we must put 74 | // an '&' charcater in front of it. 75 | 76 | swapTwoInts( &var1, &var2 ) 77 | 78 | print("var1 = \(var1), var2 = \(var2)") // After Swap 79 | 80 | 81 | //------------------------------------------------------------------------------ 82 | 83 | // Variadic Parameters 84 | 85 | // A variadic parameter allow us to pass zero or more values of a specified 86 | // type, and then get access to them. 87 | 88 | func addAllNumbers(_ numbers: Int...) -> Int { 89 | 90 | var total: Int = 0 91 | 92 | for number in numbers { 93 | total += number 94 | } 95 | 96 | return total 97 | } 98 | 99 | print( addAllNumbers( 1, 2, 3, 4, 5) ) 100 | 101 | //------------------------------------------------------------------------------ 102 | 103 | // Nested Functions 104 | 105 | // It's possible to declare a function inside another function and then use it! 106 | 107 | func processNumbers(_ number1: Int, _ number2: Int) -> Int { 108 | 109 | func add(_ a: Int, _ b: Int) -> Int { 110 | return a + b 111 | } 112 | 113 | return add(number1, number2) 114 | } 115 | 116 | let result = processNumbers(1, 2) 117 | 118 | print(result) 119 | -------------------------------------------------------------------------------- /swift_8_functions_advanced.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /swift_8_functions_advanced.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /swift_9_enumerations.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import UIKit 3 | 4 | 5 | // Enumerations 6 | 7 | // An enumeration defines a common type for a group of related values and 8 | // enables you to work with those values in a type-safe way within your code. 9 | 10 | enum GamePadDirection { 11 | case up 12 | case down 13 | case left 14 | case right 15 | } 16 | 17 | var gamePadInput = GamePadDirection.up 18 | 19 | print("Game pad is being pushed: \(gamePadInput).") 20 | 21 | 22 | // Now, if you're wondering why enumerations are useful, consider the typical 23 | // alternative. Instead of using an enumeration to represent the possible 24 | // Game pad Directions we could've defined a bunch of simple constants values, 25 | // but if we do this, we lose the type safety that enumerations enforce! 26 | /* 27 | let GamePadUp = 1 28 | let GamePadDown = 2 29 | let GamePadLeft = 3 30 | let GamePadRight = 4 31 | 32 | // This works and looks reasonable... so far so good! 33 | var gamePadDirection = GamePadUp 34 | 35 | // But without type safety, we can also do this which makes no sense! 36 | gamePadDirection = 55 37 | 38 | // What does the value 55 mean? Swift will not mark this an error because 55 39 | // is just as valid a value as 1,2,3, or 4 which are used by the constants. 40 | */ 41 | 42 | //------------------------------------------------------------------------------ 43 | 44 | // A switch statement is a great way to process the value of a variable that is 45 | // an enumeration type. 46 | 47 | gamePadInput = GamePadDirection.down 48 | 49 | switch gamePadInput { 50 | 51 | case .up: 52 | print("The game pad is being pushed up!") 53 | 54 | case .down: 55 | print("The game pad is being pushed down!") 56 | 57 | case .left: 58 | print("The game pad is being pushed left!") 59 | 60 | case .right: 61 | print("The game pad is being pushed right!") 62 | } 63 | 64 | //------------------------------------------------------------------------------ 65 | 66 | // Raw Values 67 | 68 | // Enumeration cases can have actual values (called raw values), assigned to them 69 | // as long as they are all of the same type and all unique. 70 | 71 | enum Team: String { 72 | case a = "Alpha" 73 | case b = "Bravo" 74 | case c = "Charlie" 75 | } 76 | 77 | var team1 = Team.a 78 | 79 | print(team1) 80 | 81 | print(team1.rawValue) 82 | 83 | // If we assign Raw Values to the enumeration's, the enumeration automatically 84 | // receives an initializer that can be used to create a new enumeration 85 | // variable by passing in one of the Raw Values. 86 | 87 | var team2 = Team(rawValue: "Bravo") 88 | 89 | print("\(team2 as Team?)") 90 | 91 | 92 | // If the raw value that was passed in can not be turned into an enumeration 93 | // the initializer will return nil. 94 | var team3 = Team(rawValue: "X-Ray") 95 | 96 | print("\(team3 as Team?)") 97 | 98 | 99 | //------------------------------------------------------------------------------ 100 | 101 | // Implicitly Assigned Raw Values 102 | 103 | // When you’re working with enumerations that store integer or string raw values, 104 | // you don’t have to explicitly assign a raw value for each case. When you don’t, 105 | // Swift will automatically assign the values for you. 106 | 107 | enum GameServerErrors: Int { 108 | 109 | case findLevelData = 500 110 | case loadLevelData // This will automatically bet set to 501 111 | 112 | case findPlayerData // This will automatically bet set to 502 113 | case loadPlayerData // This will automatically bet set to 503 114 | case savePlayerData // This will automatically bet set to 504 115 | } 116 | 117 | // If you want to know what the raw value of the enumeration value is, you can 118 | // call .rawValue on an enumeration variable to access it. 119 | 120 | var error = GameServerErrors.loadLevelData 121 | 122 | print(error.rawValue) 123 | 124 | error = GameServerErrors.savePlayerData 125 | 126 | print(error.rawValue) 127 | 128 | //------------------------------------------------------------------------------ 129 | 130 | // Associated Values 131 | 132 | // You can define Swift enumerations that are capable of storing associated 133 | // values which allow the enumeration types to be customized during assignment. 134 | 135 | enum WeaponTypes { 136 | 137 | case sword(String, Int) 138 | case bow(String, Int) 139 | case woodenClub(Int) 140 | case rock(Int) 141 | } 142 | 143 | var playerWeapon = WeaponTypes.sword("Short Sword", 25) 144 | 145 | playerWeapon = .bow("Long Bow", 10) 146 | 147 | playerWeapon = .woodenClub(2) 148 | 149 | playerWeapon = .rock(1) 150 | 151 | // Associated values can be extracted as part of a switch statement. 152 | 153 | switch playerWeapon { 154 | 155 | case .sword(let name, let damage): 156 | print("The player is attacking with a \(name) for \(damage) points of damage.") 157 | 158 | case .bow(let name, let damage): 159 | print("The player is attacking with a \(name) for \(damage) points of damage.") 160 | 161 | case .woodenClub(let damage): 162 | print("The player is attacking with a WoodenClub for \(damage) points of damage.") 163 | 164 | case .rock(let damage): 165 | print("The player is attacking with a rock for \(damage) points of damage.") 166 | } 167 | 168 | //------------------------------------------------------------------------------ 169 | 170 | // Assigning a Default Enumeration Value 171 | 172 | // If you don’t want to select a specific enumeration value when creating an 173 | // instance then you can provide an initializer method which defaults to one of 174 | // the enumeration values. 175 | 176 | enum ArmorTypes { 177 | 178 | case leather 179 | case chainMail 180 | case plate 181 | 182 | init() { 183 | 184 | // Everyone has at least Leather armor! 185 | self = .leather 186 | } 187 | } 188 | 189 | var armor = ArmorTypes() 190 | 191 | print("Default armor type is: \(armor)") 192 | 193 | -------------------------------------------------------------------------------- /swift_9_enumerations.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /swift_9_enumerations.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | --------------------------------------------------------------------------------