├── .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 |
--------------------------------------------------------------------------------