├── .gitignore
├── 01 - The Basics.playground
├── contents.xcplayground
├── playground.xcworkspace
│ └── contents.xcworkspacedata
└── section-1.swift
├── 02 - Basic Operators.playground
├── contents.xcplayground
├── playground.xcworkspace
│ └── contents.xcworkspacedata
└── section-1.swift
├── 03 - Strings and Characters.playground
├── contents.xcplayground
├── playground.xcworkspace
│ └── contents.xcworkspacedata
├── section-1.swift
└── timeline.xctimeline
├── 04 - Collection Types.playground
├── contents.xcplayground
├── playground.xcworkspace
│ └── contents.xcworkspacedata
├── section-1.swift
└── timeline.xctimeline
├── 05 - Control Flow.playground
├── contents.xcplayground
├── playground.xcworkspace
│ └── contents.xcworkspacedata
└── section-1.swift
├── 06 - Functions.playground
├── contents.xcplayground
├── playground.xcworkspace
│ └── contents.xcworkspacedata
└── section-1.swift
├── 07 - Closures.playground
├── contents.xcplayground
├── playground.xcworkspace
│ └── contents.xcworkspacedata
└── section-1.swift
├── 08 - Enumerations.playground
├── contents.xcplayground
├── playground.xcworkspace
│ └── contents.xcworkspacedata
└── section-1.swift
├── 09 - Classes and Structures.playground
├── contents.xcplayground
├── playground.xcworkspace
│ └── contents.xcworkspacedata
├── section-1.swift
└── timeline.xctimeline
├── 10 - Properties.playground
├── contents.xcplayground
├── playground.xcworkspace
│ └── contents.xcworkspacedata
└── section-1.swift
├── 11 - Methods.playground
├── contents.xcplayground
├── playground.xcworkspace
│ └── contents.xcworkspacedata
└── section-1.swift
├── 12 - Subscripts.playground
├── contents.xcplayground
├── playground.xcworkspace
│ └── contents.xcworkspacedata
├── section-1.swift
└── timeline.xctimeline
├── 13 - Inheritance.playground
├── contents.xcplayground
├── playground.xcworkspace
│ └── contents.xcworkspacedata
└── section-1.swift
├── 14 - Initialization.playground
├── contents.xcplayground
├── playground.xcworkspace
│ └── contents.xcworkspacedata
└── section-1.swift
├── 15 - Deinitialization
├── 15 - Deinitialization.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ └── contents.xcworkspacedata
└── 15 - Deinitialization
│ └── main.swift
├── 16 - Automatic Reference Counting
├── 16 - Automatic Reference Counting.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ └── contents.xcworkspacedata
└── 16 - Automatic Reference Counting
│ └── main.swift
├── 17 - Optional Chaining.playground
├── contents.xcplayground
├── playground.xcworkspace
│ └── contents.xcworkspacedata
└── section-1.swift
├── 18 - Type Casting.playground
├── contents.xcplayground
├── playground.xcworkspace
│ └── contents.xcworkspacedata
└── section-1.swift
├── 19 - Nested Types.playground
├── contents.xcplayground
├── playground.xcworkspace
│ └── contents.xcworkspacedata
└── section-1.swift
├── 20 - Extensions
├── 20 - Extensions.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ └── contents.xcworkspacedata
└── 20 - Extensions
│ └── main.swift
├── 21 - Protocols.playground
├── contents.xcplayground
├── playground.xcworkspace
│ └── contents.xcworkspacedata
└── section-1.swift
├── 22 - Generics.playground
├── contents.xcplayground
├── playground.xcworkspace
│ └── contents.xcworkspacedata
└── section-1.swift
├── 23 - Access Control.playground
├── contents.xcplayground
├── playground.xcworkspace
│ └── contents.xcworkspacedata
└── section-1.swift
├── 24 - Advanced Operators.playground
├── contents.xcplayground
├── playground.xcworkspace
│ └── contents.xcworkspacedata
└── section-1.swift
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | # Mac OS X
2 | .DS_Store
3 |
4 | # Xcode
5 | build/
6 | *.pbxuser
7 | !default.pbxuser
8 | *.mode1v3
9 | !default.mode1v3
10 | *.mode2v3
11 | !default.mode2v3
12 | *.perspectivev3
13 | !default.perspectivev3
14 | xcuserdata
15 | *.xccheckout
16 | *.moved-aside
17 | DerivedData
18 | *.hmap
19 | *.ipa
20 | *.xcuserstate
21 |
--------------------------------------------------------------------------------
/01 - The Basics.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/01 - The Basics.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/01 - The Basics.playground/section-1.swift:
--------------------------------------------------------------------------------
1 |
2 | //=======================================
3 | // Constants and Variables
4 | //=======================================
5 |
6 | // Constants use let
7 | let maximumNumberOfInputs = 10
8 |
9 | // Variables use var
10 | var str = "Hello, playground"
11 | var currentLoginAttempts = 0
12 | var x = 0.0, y = 0.0, z = 1.0
13 |
14 | // Defining multiple values as a type
15 | var red, green, blue: Double
16 |
17 | // Variable without initial value
18 | var welcomeMessage: String
19 | //println(welcomeMessage) // errors if used before initialized
20 | welcomeMessage = "Hello, Christian"
21 |
22 | // Changing Variable Values
23 | var friendlyWelcome = "Hello"
24 | friendlyWelcome = "Bonjour!"
25 |
26 | // Changing Constant Values (cannot do it)
27 | let languageName = "Swift"
28 | //languageName = "ObjC" // Compiler error
29 |
30 | // println adds a newline at the end
31 | print(languageName)
32 | print(languageName)
33 |
34 | //=======================================
35 | // Comments
36 | //=======================================
37 |
38 | // Comment 1
39 | /* Comment 2 */
40 |
41 | //=======================================
42 | // Semicolons
43 | //=======================================
44 |
45 | let cat = "[]" ; print(cat)
46 |
47 | //=======================================
48 | // Integers
49 | //=======================================
50 |
51 | // Int Bounds
52 | let minValue = UInt8.min
53 | let maxValue = UInt8.max
54 |
55 | // Int Sizes
56 | let value8bits: UInt8 = 27
57 | let value16bits: UInt16 = 27
58 | let value32bits: UInt32 = 27
59 | let value64bits: UInt64 = 27
60 |
61 | // Numbers
62 | var decimalValue = 3.14159 // Double by default
63 | var decimalValueFloat: Float = 3.14159
64 | var anotherPi = 3 + 0.14159 // this will be a double also
65 | var binaryInteger = 0b001010
66 | var octalInteger = 0o21
67 | var hexadecimalInteger = 0x42
68 |
69 | // Numeric literals
70 | let decimalDouble = 12.123_456
71 | let bigValue = 1_000_000_123.123
72 |
73 | //=======================================
74 | // Numeric Type Conversions
75 | //=======================================
76 |
77 | // Up-converting ints
78 | let twoThousand: UInt16 = 2_000
79 | let one: UInt8 = 1
80 | let twoThousandAndOne = twoThousand + UInt16(one)
81 |
82 | // Down-converting doubles to ints
83 | let three = 3 // Integer
84 | let pointOneFourOneFiveNine = 0.14159 // Double
85 | let piDouble = Double(three) + pointOneFourOneFiveNine
86 | let piInteger = three + Int(pointOneFourOneFiveNine)
87 |
88 | //=======================================
89 | // Type Aliases
90 | //=======================================
91 |
92 | typealias AudioSample = UInt16
93 | var maxAmplitudeFound = AudioSample.min
94 | var minAmplitudeFound = AudioSample.max
95 |
96 | //=======================================
97 | // Booleans
98 | //=======================================
99 |
100 | let orangesAreOrange = true
101 | let turnipsAreDelicious = false
102 |
103 | // Can only evaluate booleans in conditionals
104 | if turnipsAreDelicious {
105 | print("Mmmm, tasty turnips")
106 | } else {
107 | print("Ewww, turnips are horrible")
108 | }
109 |
110 | let i = 1
111 | if i == 1 {
112 | print("Magic")
113 | }
114 |
115 | //=======================================
116 | // Tuples
117 | //=======================================
118 |
119 | // Create a tuple
120 | let http404Error = (404, "Not Found")
121 | print(http404Error)
122 |
123 | // Pull all values back out
124 | let (statusCode, statusMessage) = http404Error
125 | print("The status code is \(statusCode)")
126 | print("The status message is \(statusMessage)")
127 |
128 | // Pull only one value back out
129 | let (onlyStatusCode, _) = http404Error
130 | print("The status code is \(statusCode)")
131 |
132 | // Access individual elements of the tuple w/o pulling them out
133 | print("The status code is \"\(http404Error.0)\"")
134 | print("The status message is \"\(http404Error.1)\"")
135 |
136 | // Name individual tuple elements
137 | let http200Status = (statusCode: 200, description: "OKAY")
138 | print("The status code is \"\(http200Status.statusCode)\"")
139 | print("The description is \"\(http200Status.description)\"")
140 |
141 | //=======================================
142 | // Optionals
143 | //=======================================
144 |
145 | // Convert string to int
146 | let possibleNumber = "123"
147 | let convertedNumber: Int? = Int(possibleNumber)
148 | print("Integer: \(convertedNumber)")
149 |
150 | // You can only nil out an optional
151 | var serverResponseCode: Int? = 404
152 | serverResponseCode = nil
153 | var actualResponseCode = 404
154 | //actualResponseCode = nil // throws compiler error
155 |
156 | // Optionals w/o a value default to nil
157 | var surveyAnswer: String?
158 |
159 | // If statements and forced unwrapping
160 | if convertedNumber != nil {
161 | print("convertedNumber contains integer.")
162 | }
163 |
164 | if convertedNumber != nil {
165 | print("convertedNumber == \(convertedNumber)") // still an optional
166 | print("convertedNumber == \(convertedNumber!)") // grabs the integer value
167 | }
168 |
169 | // Optional binding
170 | if let actualNumber = Int(possibleNumber){
171 | print("\(possibleNumber) has an integer value of \(actualNumber)")
172 | }
173 | else {
174 | print("\(possibleNumber) could not be converted to an integer")
175 | }
176 |
177 | // Implicitly unwrapped optionals
178 | let possibleString: String? = "An optional string."
179 | let forcedString: String = possibleString! // requires the exclamation mark
180 |
181 | let assumedString: String! = "An implicitly unwrapped optional string."
182 | let implicitString: String = assumedString
183 |
184 | if assumedString != nil {
185 | print(assumedString)
186 | }
187 |
188 | if let definiteString = assumedString {
189 | print(definiteString)
190 | }
191 |
192 | //=======================================
193 | // Assertions
194 | //=======================================
195 |
196 | let age = -3
197 | //assert(age >= 0, "A person's age cannot be less than zero") // will trigger assert
198 |
--------------------------------------------------------------------------------
/02 - Basic Operators.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/02 - Basic Operators.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/02 - Basic Operators.playground/section-1.swift:
--------------------------------------------------------------------------------
1 |
2 | //=======================================
3 | // Terminology
4 | //=======================================
5 |
6 | //-i // Unary
7 | //a + b // Binary
8 | //a ? b : c // Ternary
9 |
10 | //=======================================
11 | // Assignment Operator
12 | //=======================================
13 |
14 | let b = 10
15 | var a = 5
16 | a = b
17 |
18 | let (x, y) = (1, 2)
19 | print(x)
20 | print(y)
21 |
22 | //if x = y {
23 | // this is not valid b/c x = y does not return a value
24 | //}
25 |
26 | let possibleValue: Int? = 10
27 | if let actualValue = possibleValue {
28 | print("this is valid")
29 | }
30 |
31 | //=======================================
32 | // Arithmetic Operators
33 | //=======================================
34 |
35 | // Basic arithmetic operators with numbers
36 | 1 + 2
37 | 5 - 3
38 | 2 * 3
39 | 10.0 / 2.5
40 |
41 | // Basic arithmetic operators with strings and characters
42 | "hello, " + "world"
43 | var dog: Character = "*"
44 | let cow: Character = "*"
45 | let dogCow = String(dog) + String(cow)
46 |
47 | //=======================================
48 | // Remainder Operator
49 | //=======================================
50 |
51 | // Integer remainders
52 | 9 % 4
53 | -9 % 4
54 |
55 | // Float remainders
56 | 8 % 2.5
57 |
58 | //=======================================
59 | // Unary Operators
60 | //=======================================
61 |
62 | // Unary Minus Operator
63 | let three = 3
64 | let minusThree = -three
65 | let plusThree = -minusThree
66 |
67 | // Unary Plus Operator
68 | let minusSix = -6
69 | let alsoMinusSix = +minusSix // pointless, never use!
70 |
71 | //=======================================
72 | // Compound Assignment Operators
73 | //
74 | // = Assign
75 | // *= Multiply and assign
76 | // /= Divide and assign
77 | // %= Remainder and assign
78 | // += Add and assign
79 | // -= Subtract and assign
80 | // <<= Left bit shift and assign
81 | // >>= Right bit shift and assign
82 | // &= Bitwise AND and assign
83 | // ^= Bitwise XOR and assign
84 | // |= Bitwise OR and assign
85 | // &&= Logical AND and assign
86 | // ||= Logical OR and assign
87 | //
88 | //=======================================
89 |
90 | var f = 1
91 | f += 2 // equals f = f + 2
92 | f -= 2 // equals f = f - 2
93 |
94 | //=======================================
95 | // Comparison Operators
96 | //=======================================
97 |
98 | 1 == 1
99 | 2 != 1
100 | 2 > 1
101 | 1 < 2
102 | 1 >= 1
103 | 2 <= 1
104 |
105 | let name = "world"
106 |
107 | if name == "world" {
108 | print("hello, world")
109 | } else {
110 | print("I'm sorry \(name), but I don't recognize you")
111 | }
112 |
113 | //=======================================
114 | // Ternary Conditional Operator
115 | //=======================================
116 |
117 | let contentHeight = 40
118 | let hasHeader = true
119 | let rowHeight = contentHeight + (hasHeader ? 50 : 20)
120 |
121 | //=======================================
122 | // Nil Coalescing Operator
123 | //=======================================
124 |
125 | let optionalValue: Int? = 10
126 | var actualValue = 5
127 | optionalValue != nil ? optionalValue! : actualValue
128 | optionalValue ?? actualValue
129 |
130 | let defaultColorName = "red"
131 | var userDefinedColorName: String? // defaults to nil
132 | var colorNameToUse = userDefinedColorName ?? defaultColorName
133 |
134 | userDefinedColorName = "green"
135 | colorNameToUse = userDefinedColorName ?? defaultColorName
136 |
137 | //=======================================
138 | // Range Operators
139 | //=======================================
140 |
141 | // Closed Range Operator
142 | for index in 1...5 {
143 | print("\(index) times 5 is \(index * 5)")
144 | }
145 |
146 | // Half-Open Range Operator
147 | let names = ["Anna", "Alex", "Brian", "Jack"]
148 |
149 | for index in 0..
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/03 - Strings and Characters.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/03 - Strings and Characters.playground/section-1.swift:
--------------------------------------------------------------------------------
1 |
2 | //=======================================
3 | // String Literals
4 | //=======================================
5 |
6 | // Basic string literal
7 | let someString = "Some string literal value"
8 |
9 | // Initializing empty strings
10 | var emptyString = ""
11 | var anotherEmptyString = String()
12 |
13 | if emptyString.isEmpty && anotherEmptyString.isEmpty {
14 | print("Nothing to see here")
15 | }
16 |
17 | // String mutability
18 | var variableString = "Horse"
19 | variableString += " and carriage"
20 |
21 | let constantString = "Highlander"
22 | //constantString += " and another Highlander" // compile-time error
23 |
24 | //=======================================
25 | // Working with Characters
26 | //=======================================
27 |
28 | // Iterating through characters
29 | for character in "Baby chick!🐥".characters {
30 | print(character)
31 | }
32 |
33 | // Creating characters directly
34 | let yenSign: Character = "¥"
35 |
36 | // Concatenating Strings and Characters
37 | let string1 = "hello"
38 | let string2 = " there"
39 | var welcome = string1 + string2
40 |
41 | var instruction = "look over"
42 | instruction += string2
43 |
44 | let exclamationMark: Character = "!"
45 | welcome.append(exclamationMark)
46 | print(welcome)
47 |
48 | // String interpolation
49 | let multiplier = 3
50 | let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"
51 |
52 | //=======================================
53 | // Unicode
54 | //=======================================
55 |
56 | // Unicode scalars
57 | let latinSmallLetterA: Character = "a"
58 | let frontFacingBabyChick: Character = "🐥"
59 | let dollarSignCharacter: Character = "\u{24}"
60 | let blackHeartCharacter: Character = "\u{2665}"
61 | let sparklingHeartCharacter: Character = "\u{1F496}"
62 |
63 | // Special Unicode Characters in String Literals
64 | let wiseWords = "\"Imagination is more important than knowledge\" - Einstein"
65 | let dollarSign = "\u{24}" // $, Unicode scalar U+0024
66 | let blackHeart = "\u{2665}" // ♥, Unicode scalar U+2665
67 | let sparklingHeart = "\u{1F496}" // 💖, Unicode scalar U+1F496
68 |
69 | // Extended Grapheme Clusters
70 | let eAcute: Character = "\u{E9}"
71 | let combinedEAcute: Character = "\u{65}\u{301}" // e followed by ́ equals é
72 |
73 | let precomposed: Character = "\u{D55C}" // 한
74 | let decomposed: Character = "\u{1112}\u{1161}\u{11AB}" // ᄒ, ᅡ, ᆫ
75 |
76 | let enclosedEAcute: Character = "\u{E9}\u{20DD}"
77 |
78 | //=======================================
79 | // Counting Characters
80 | //=======================================
81 |
82 | // countElements global function
83 | let unusualMenagerie = "Koala 🐨, Snail 🐌, Penguin 🐧, Dromedary 🐪"
84 | print("unusualMenagerie has \(unusualMenagerie.characters.count) characters")
85 |
86 | // Character count with Extreme Grapheme Clusters
87 | var word = "cafe"
88 | print("the number of characters in \(word) is \((word).characters.count)")
89 |
90 | word += "\u{301}"
91 | print("the number of characters in \(word) is \((word).characters.count)")
92 |
93 | var emoji = "👍"
94 | emoji.characters.count
95 |
96 | //=======================================
97 | // Comparing Strings
98 | //=======================================
99 |
100 | // String and Character Equality
101 | let quotation = "We're a lot alike, you and I."
102 | let sameQuotation = "We're a lot alike, you and I."
103 |
104 | if quotation == sameQuotation {
105 | print("These two strings are considered equal")
106 | }
107 |
108 | // Even if extreme grapheme clusters are different, if they visually appear the same,
109 | // then they are equal
110 | let eAcuteQuestion = "Voulez-vous un caf\u{E9}"
111 | let combinedEAcuteQuestion = "Voulez-vous un caf\u{65}\u{301}"
112 |
113 | if eAcuteQuestion == combinedEAcuteQuestion {
114 | print("These two strings are considered equal")
115 | }
116 |
117 | // The English capital A is not equal to the Russian capital A b/c
118 | // they are visually different
119 | let latinCapitalLetterA: Character = "\u{41}"
120 | let cyrillicCapitalLetterA: Character = "\u{0410}"
121 |
122 | if latinCapitalLetterA != cyrillicCapitalLetterA {
123 | print("These two characters are not equivalent")
124 | }
125 |
126 | // Prefix Equality
127 | let romeoAndJuliet = [
128 | "Act 1 Scene 1: Verona, A public place",
129 | "Act 1 Scene 2: Capulet's mansion",
130 | "Act 1 Scene 3: A room in Capulet's mansion",
131 | "Act 1 Scene 4: A street outside Capulet's mansion",
132 | "Act 1 Scene 5: The Great Hall in Capulet's mansion",
133 | "Act 2 Scene 1: Outside Capulet's mansion",
134 | "Act 2 Scene 2: Capulet's orchard",
135 | "Act 2 Scene 3: Outside Friar Lawrence's cell",
136 | "Act 2 Scene 4: A street in Verona",
137 | "Act 2 Scene 5: Capulet's mansion",
138 | "Act 2 Scene 6: Friar Lawrence's cell"
139 | ]
140 |
141 | var act1SceneCount = 0
142 |
143 | for scene in romeoAndJuliet where scene.hasPrefix("Act 1 ") {
144 | act1SceneCount += 1
145 | }
146 |
147 | print("There are \(act1SceneCount) scenes in Act 1")
148 |
149 | // Suffix Equality
150 | var mansionCount = 0
151 | var cellCount = 0
152 |
153 | for scene in romeoAndJuliet {
154 | if scene.hasSuffix("Capulet's mansion") {
155 | mansionCount += 1
156 | } else if scene.hasSuffix("Friar Lawrence's cell") {
157 | cellCount += 1
158 | }
159 | }
160 |
161 | print("\(mansionCount) mansion scenes and \(cellCount) cell scenes")
162 |
163 | //=======================================
164 | // Unicode Representations of Strings
165 | //=======================================
166 |
167 | let dogString = "Dog\u{203C}\u{1F436}"
168 |
169 | // UTF-8 Representation
170 | for codeUnit in dogString.utf8 {
171 | print("\(codeUnit) ")
172 | }
173 |
174 | print()
175 |
176 | // 68 111 103 226 128 188 240 159 144 182
177 | // D o g [ !! ] [ 🐶 ]
178 | // 1b 1b 1b 3b 4b // b = byte
179 |
180 | // UTF-16 Representation
181 | for codeUnit in dogString.utf16 {
182 | print("\(codeUnit) ")
183 | }
184 |
185 | print()
186 |
187 | // 68 111 103 8252 55357 56374
188 | // D o g !! [ 🐶 ]
189 | // 2b 2b 2b 2b 4b // b = byte
190 |
191 | // Unicode Scalar Representation
192 | for scalar in dogString.unicodeScalars {
193 | print("\(scalar.value) ")
194 | }
195 |
196 | print()
197 |
198 | // 68 111 103 8252 128054
199 | // D o g !! 🐶
200 | // 4b 4b 4b 4b 4b // b = byte
201 |
202 | // Print out individual unicode scalars
203 | for scalar in dogString.unicodeScalars {
204 | print("\(scalar)")
205 | }
206 |
--------------------------------------------------------------------------------
/03 - Strings and Characters.playground/timeline.xctimeline:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/04 - Collection Types.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/04 - Collection Types.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/04 - Collection Types.playground/section-1.swift:
--------------------------------------------------------------------------------
1 |
2 | //=======================================
3 | // Arrays
4 | //=======================================
5 |
6 | // Array Literals
7 | var genericShoppingList: Array = ["Eggs", "Milk"]
8 | var shoppingList: [String] = ["Eggs", "Milk"]
9 | var shorthandShoppingList = ["Eggs", "Milk"]
10 |
11 | // Accessing and modifying an array
12 | print("The shopping list contains \(shoppingList.count) items.")
13 |
14 | if shoppingList.isEmpty {
15 | print("The shopping list is empty.")
16 | } else {
17 | print("The shopping list is NOT empty.")
18 | }
19 |
20 | // Multiple ways to add items to the array
21 | shoppingList.append("Flour")
22 | shoppingList += ["Baking Powder"]
23 | shoppingList += ["Chocolate Spread", "Cheese", "Butter"]
24 | print(shoppingList)
25 |
26 | // Retrieve values
27 | var firstItem = shoppingList[0]
28 | print(shoppingList)
29 |
30 | // Modify values
31 | shoppingList[0] = "Six Eggs"
32 | print(shoppingList)
33 | shoppingList[4...6] = ["Bananas", "Apples"]
34 | print(shoppingList)
35 |
36 | // Insert values
37 | shoppingList.insert("Maple Syrup", atIndex: 0)
38 | print(shoppingList)
39 |
40 | // Remove values
41 | let mapleSyrup = shoppingList.removeAtIndex(0)
42 | firstItem = shoppingList[0]
43 | print(shoppingList)
44 |
45 | let apples = shoppingList.removeLast()
46 | print(shoppingList)
47 |
48 | // Iterating over an array
49 | for item in shoppingList {
50 | print(item)
51 | }
52 |
53 | for (index, value) in shoppingList.enumerate() {
54 | print("Item \(index + 1): \(value)")
55 | }
56 |
57 | // Creating and initializing an array
58 | var someInts = [Int]()
59 | print("someInts is of type [Int] with \(someInts.count) items.")
60 |
61 | someInts.append(3) // contains 1 value of type Int
62 | someInts = [] // now empty array, but still of type [Int]
63 |
64 | var threeDoubles = [Double](count: 3, repeatedValue: 0.0)
65 | var anotherThreeDoubles = [Double](count: 3, repeatedValue: 2.5)
66 | var sixDoubles = threeDoubles + anotherThreeDoubles
67 |
68 | //=======================================
69 | // Dictionaries
70 | //=======================================
71 |
72 | // Create a dictionary
73 | var longAirports: [String: String] = ["TYO": "Tokyo", "DUB": "Dublin", "PDX": "Portland"]
74 | var airports = ["TYO": "Tokyo", "DUB": "Dublin", "PDX": "Portland"] // infers [String: String] as type
75 |
76 | // Accessing and Modifying a Dictionary
77 | print("The airports dictionary contains \(airports.count) items.")
78 |
79 | if airports.isEmpty {
80 | print("The airports dictionary is empty.")
81 | } else {
82 | print("The airports dictionary is NOT empty.")
83 | }
84 |
85 | // Add item to dictionary
86 | airports["LHR"] = "London"
87 | print(airports)
88 |
89 | // Replace item value
90 | airports["LHR"] = "London Heathrow"
91 | print(airports)
92 |
93 | // Replace item value while retrieving old value
94 | let oldLHR = airports.updateValue("London", forKey: "LHR")
95 | if oldLHR != nil {
96 | let newLHR = airports["LHR"]
97 | print("Swapped \(newLHR!) out for \(oldLHR!) for the LHR airport")
98 | }
99 |
100 | // Replace item value directly in conditional
101 | if let evenOlderLHR = airports.updateValue("London Heathrow", forKey: "LHR") {
102 | let newLHR = airports["LHR"]
103 | print("Replaced \(evenOlderLHR) with \(newLHR!) for LHR airport")
104 | }
105 |
106 | // Replace item value in conditional where value doesn't exist
107 | if let oldMCI = airports.updateValue("Kansas City", forKey: "MCI") {
108 | let newMCI = airports["MCI"]
109 | print("Replaced \(oldMCI) with \(newMCI!) for MCI airport")
110 | } else {
111 | let MCI = airports["MCI"]
112 | print("Added the \(MCI!) airport under the MCI code")
113 | }
114 |
115 | // Retrieving items out of the dictionary
116 | if let airportName = airports["DUB"] {
117 | print("The name of the airport is \(airportName)")
118 | } else {
119 | print("That airport is not in the airports dictionary")
120 | }
121 |
122 | // Removing an item from a dictionary
123 | print(airports)
124 | airports["DUB"] = nil
125 | print(airports)
126 |
127 | // Removing an item from a dictionary while retrieving old item
128 | if let removedValue = airports.removeValueForKey("LHR") {
129 | print("The removed airport's name is \(removedValue)")
130 | } else {
131 | print("The airports dictionary does not contain a value for LHR")
132 | }
133 |
134 | // Iterating over a dictionary
135 | for (airportCode, airportName) in airports {
136 | print("\(airportCode): \(airportName)")
137 | }
138 |
139 | // Iterating over the dictionary's keys
140 | for airportCode in airports.keys {
141 | print("\(airportCode)")
142 | }
143 |
144 | // Iterating over the dictionary's values
145 | for airportName in airports.values {
146 | print("\(airportName)")
147 | }
148 |
149 | // Storing the array of keys or values of a dictionary
150 | let airportCodes = [String](airports.keys)
151 | let airportNames = [String](airports.values)
152 |
153 | // Creating empty dictionaries
154 | var longNamesOfIntegers = Dictionary()
155 | var namesOfIntegers = [Int: String]()
156 |
157 | namesOfIntegers[16] = "sixteen"
158 | print(namesOfIntegers)
159 | namesOfIntegers = [:] // resets dictionary to be empty of type [Int: String]
160 | print(namesOfIntegers)
161 |
--------------------------------------------------------------------------------
/04 - Collection Types.playground/timeline.xctimeline:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/05 - Control Flow.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/05 - Control Flow.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/05 - Control Flow.playground/section-1.swift:
--------------------------------------------------------------------------------
1 |
2 | //=======================================
3 | // For-In Loops
4 | //=======================================
5 |
6 | // Range iteration
7 | for index in 1...5 {
8 | print("\(index) times 5 is \(index * 5)")
9 | }
10 |
11 | // Range iteration while ignoring index
12 | let base = 3
13 | let power = 10
14 | var answer = 1
15 |
16 | for _ in 1...power {
17 | answer *= base
18 | }
19 |
20 | print("\(base) to the power of \(power) is \(answer)")
21 |
22 | // Array iteration
23 | let names = ["Christian", "Eric", "Jereme", "Ron"]
24 |
25 | for name in names {
26 | print("Hello \(name)")
27 | }
28 |
29 | // Dictionary iteration (no guarantee about iteration order here...)
30 | let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
31 |
32 | for (animalName, legCount) in numberOfLegs {
33 | print("\(animalName)s have \(legCount) legs")
34 | }
35 |
36 | // String character iteration
37 | for character in "Hello".characters {
38 | print(character)
39 | }
40 |
41 | //=======================================
42 | // For Loops
43 | //=======================================
44 |
45 | for index in 0..<3 {
46 | print("index is \(index)")
47 | }
48 |
49 | var index: Int = 0
50 |
51 | for _ in 0..<3 {
52 | print("index is \(index)")
53 | index += 1
54 | }
55 |
56 | print("The loop statements were executed \(index) times")
57 |
58 | //=======================================
59 | // While Loops
60 | //=======================================
61 |
62 | // Basic structure
63 | var counter = 0
64 |
65 | while counter < 3 {
66 | print("I be loopin'")
67 | counter += 1
68 | }
69 |
70 | print()
71 |
72 | //=======================================
73 | // Do-While Loops
74 | //=======================================
75 |
76 | // Basic structure
77 | counter = 0
78 |
79 | repeat {
80 | print("I be loopin'")
81 | counter += 1
82 | } while counter < 3
83 |
84 | print()
85 |
86 | //=======================================
87 | // If Statements
88 | //=======================================
89 |
90 | // if condition
91 | var temperatureInFahrenheit = 30
92 |
93 | if temperatureInFahrenheit <= 32 {
94 | print("It's very cold. Consider wearing a scarf.")
95 | }
96 |
97 | // if / else condition
98 | temperatureInFahrenheit = 40
99 |
100 | if temperatureInFahrenheit <= 32 {
101 | print("It's very cold. Consider wearing a scarf.")
102 | } else {
103 | print("It's not that cold. Wear a t-shirt.")
104 | }
105 |
106 | // if / else if / else condition
107 | temperatureInFahrenheit = 90
108 |
109 | if temperatureInFahrenheit <= 32 {
110 | print("It's very cold. Consider wearing a scarf.")
111 | } else if temperatureInFahrenheit >= 86 {
112 | print("It's really warm. Don't forget to wear sunscreen.")
113 | } else {
114 | print("It's not that cold. Wear a t-shirt.")
115 | }
116 |
117 | // if / else if condition
118 | temperatureInFahrenheit = 72
119 |
120 | if temperatureInFahrenheit <= 32 {
121 | print("It's very cold. Consider wearing a scarf.")
122 | } else if temperatureInFahrenheit >= 86 {
123 | print("It's really warm. Don't forget to wear sunscreen.")
124 | }
125 |
126 | //=======================================
127 | // Switch Statements
128 | //=======================================
129 |
130 | // Basic structure
131 | let someCharacter: Character = "e"
132 |
133 | switch someCharacter {
134 | case "a", "e", "i", "o", "u":
135 | print("\(someCharacter) is a vowel")
136 | case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m", "n", "p",
137 | "q", "r", "s", "t", "v", "w", "x", "y", "z":
138 | print("\(someCharacter) is a consonant")
139 | default:
140 | print("\(someCharacter) is not a vowel or a consonant")
141 | }
142 |
143 | // Case statements can stack
144 | let anotherCharacter: Character = "a"
145 |
146 | switch anotherCharacter {
147 | case "a", "A":
148 | print("The letter A")
149 | default:
150 | print("Not the letter A")
151 | }
152 |
153 | // Range Matching
154 | let count = 3_000_000_000_000
155 | let countedThings = "stars in the Milky Way"
156 | var naturalCount: String
157 |
158 | switch count {
159 | case 0:
160 | naturalCount = "no"
161 | case 1...3:
162 | naturalCount = "a few"
163 | case 4...9:
164 | naturalCount = "several"
165 | case 10...99:
166 | naturalCount = "tens of"
167 | case 100...999:
168 | naturalCount = "hundreds of"
169 | case 1_000...999_999:
170 | naturalCount = "thousands of"
171 | default:
172 | naturalCount = "millions and millions of"
173 | }
174 |
175 | print("There are \(naturalCount) \(countedThings)")
176 |
177 | // Tuples
178 | let somePoint = (1, 1)
179 |
180 | switch somePoint {
181 | case (0, 0):
182 | print("(0, 0) is at the origin")
183 | case (_, 0):
184 | print("(\(somePoint.0), 0) is on the x-axis")
185 | case (0, _):
186 | print("(0, \(somePoint.1)) is on the y-axis")
187 | case (-2...2, -2...2):
188 | print("(\(somePoint.0), \(somePoint.1)) is inside the box")
189 | default:
190 | print("(\(somePoint.0), \(somePoint.1)) is outside of the box")
191 | }
192 |
193 | // Tuple value binding with constants
194 | let anotherPoint = (2, 0)
195 |
196 | switch anotherPoint {
197 | case (let x, 0):
198 | print("on the x-axis with an x value of \(x)")
199 | case (0, let y):
200 | print("on the y-axis with an y value of \(y)")
201 | case let (x, y):
202 | print("somewhere else at (\(x), \(y))")
203 | }
204 |
205 | // Tuple value binding with variables (notice myPoint does not change even though the variables change)
206 | let myPoint = (10, 20)
207 |
208 | switch myPoint {
209 | case (var x, 0):
210 | x += 1
211 | print("on the x-axis with an x value of \(x)")
212 | case (0, var y):
213 | y += 1
214 | print("on the y-axis with an y value of \(y)")
215 | case var (x, y):
216 | x += 1
217 | y -= 1
218 | print("somewhere else at (\(x), \(y))")
219 | }
220 |
221 | print("anotherPoint: (\(myPoint.0), \(myPoint.1))")
222 |
223 | // Where clause
224 | let yetAnotherPoint = (1, -1)
225 |
226 | switch yetAnotherPoint {
227 | case let (x, y) where x == y:
228 | print("(\(x), \(y)) is on the line x == y")
229 | case let (x, y) where x == -y:
230 | print("(\(x), \(y)) is on the line x == -y")
231 | case let (x, y):
232 | print("(\(x), \(y)) is is just some arbitrary point")
233 | }
234 |
235 | //=======================================
236 | // Control Transfer Statements
237 | //=======================================
238 |
239 | // Continue
240 | let puzzleInput = "great minds think alike"
241 | var puzzleOutput = ""
242 |
243 | for character in puzzleInput.characters {
244 | switch character {
245 | case "a", "e", "i", "o", "u", " ":
246 | continue
247 | default:
248 | puzzleOutput.append(character)
249 | }
250 | }
251 |
252 | print(puzzleOutput)
253 |
254 | // Break
255 | let numberSymbol: Character = "三" // Simplified Chinese for the number 3
256 | var possibleIntegerValue: Int?
257 |
258 | switch numberSymbol {
259 | case "1", "١", "一", "๑": // Latin, Arabic, Chinese, Thai values for 1
260 | possibleIntegerValue = 1
261 | case "2", "٢", "二", "๒": // Latin, Arabic, Chinese, Thai values for 2
262 | possibleIntegerValue = 2
263 | case "3", "٣", "三", "๓": // Latin, Arabic, Chinese, Thai values for 3
264 | possibleIntegerValue = 3
265 | case "4", "٤", "四", "๔": // Latin, Arabic, Chinese, Thai values for 4
266 | possibleIntegerValue = 4
267 | default:
268 | break
269 | }
270 |
271 | if let integerValue = possibleIntegerValue {
272 | print("The integer value of \(numberSymbol) is \(integerValue)")
273 | } else {
274 | print("An integer value could not be found for \(numberSymbol)")
275 | }
276 |
277 | // Fallthrough
278 | let integerToDescribe = 5
279 | var description = "The number \(integerToDescribe) is"
280 |
281 | switch integerToDescribe {
282 | case 2, 3, 5, 7, 11, 13, 17, 19:
283 | description += " a prime number, and also"
284 | fallthrough
285 | default:
286 | description += " an integer"
287 | }
288 |
289 | print(description)
290 |
291 | // Labeled Statements (this example could use more temp variables for readability)
292 | let finalSquare = 25
293 | var board = [Int](count: finalSquare + 1, repeatedValue: 0)
294 | board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
295 | board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
296 | var square = 0
297 | var diceRoll = 0
298 |
299 | gameLoop: while square != finalSquare {
300 | diceRoll += 1
301 |
302 | if diceRoll == 7 { diceRoll = 1 }
303 |
304 | switch square + diceRoll {
305 | case finalSquare:
306 | // diceRoll will move us to the final square, so the game is over
307 | break gameLoop
308 | case let newSquare where newSquare > finalSquare:
309 | // diceRoll will move us beyond the final square, so roll again
310 | continue gameLoop
311 | default:
312 | // this is a valid move, so find out its effect
313 | square += diceRoll
314 | square += board[square]
315 | }
316 | }
317 |
318 | print("Game over!")
319 |
--------------------------------------------------------------------------------
/06 - Functions.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/06 - Functions.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/06 - Functions.playground/section-1.swift:
--------------------------------------------------------------------------------
1 |
2 | //=======================================
3 | // Defining and Calling Functions
4 | //=======================================
5 |
6 | // Create a function and call it
7 | func sayHello(personName: String) -> String {
8 | let greeting = "Hello, \(personName)!"
9 | return greeting
10 | }
11 |
12 | sayHello("Christian")
13 | sayHello("Eric")
14 |
15 | // Combine return statement
16 | func sayHelloAgain(personName: String) -> String {
17 | return "Hello again, \(personName)!"
18 | }
19 |
20 | sayHelloAgain("Christian")
21 | sayHelloAgain("Eric")
22 |
23 | //=======================================
24 | // Parameters and Return Values
25 | //=======================================
26 |
27 | // Multiple input parameters
28 | func halfOpenRangeLength(start: Int, end: Int) -> Int {
29 | return end - start
30 | }
31 |
32 | halfOpenRangeLength(1, end: 10)
33 |
34 | // Function without parameters
35 | func sayHelloWorld() -> String {
36 | return "Hello World!"
37 | }
38 |
39 | sayHelloWorld()
40 |
41 | // Functions without return values
42 | func sayGoodbye(personName: String) {
43 | print("Goodbye \(personName)!")
44 | }
45 |
46 | sayGoodbye("Christian")
47 |
48 | // Ignoring function return values
49 | func printAndCount(stringToPrint: String) -> Int {
50 | print(stringToPrint)
51 | return (stringToPrint).characters.count
52 | }
53 |
54 | func printWithoutCounting(stringToPrint: String) {
55 | printAndCount(stringToPrint)
56 | }
57 |
58 | printAndCount("Hello World!") // returns 12 but we ignore it
59 | printWithoutCounting("Hello World!") // does not return value
60 |
61 | // Multiple return values
62 | func minMax(array: [Int]) -> (min: Int, max: Int) {
63 | var currentMin = array[0]
64 | var currentMax = array[0]
65 |
66 | for value in array[1.. currentMax {
70 | currentMax = value
71 | }
72 | }
73 |
74 | return (currentMin, currentMax)
75 | }
76 |
77 | minMax([8, -6, 2, 109, 3, 71])
78 |
79 | // Optional tuple return types
80 | func minMaxWithCheck(array: [Int]) -> (min: Int, max: Int)? {
81 | if array.isEmpty {
82 | return nil
83 | }
84 |
85 | var currentMin = array[0]
86 | var currentMax = array[0]
87 |
88 | for value in array[1.. currentMax {
92 | currentMax = value
93 | }
94 | }
95 |
96 | return (currentMin, currentMax)
97 | }
98 |
99 | //minMax([]) // runtime error
100 | minMaxWithCheck([])
101 | minMaxWithCheck([8, -6, 2, 109, 3, 71])
102 |
103 | if let bounds = minMaxWithCheck([8, -6, 2, 109, 3, 71]) {
104 | print("min is \(bounds.min) and max is \(bounds.max)")
105 | }
106 |
107 | //=======================================
108 | // Parameter Names
109 | //=======================================
110 |
111 | // Local parameters
112 | func join(s1: String, s2: String, joiner: String) -> String {
113 | return s1 + joiner + s2
114 | }
115 |
116 | join("Hello", s2: "World", joiner: ", ")
117 |
118 | // External parameters
119 | func join(string s1: String, toString s2: String, withJoiner joiner: String) -> String {
120 | return s1 + joiner + s2
121 | }
122 |
123 | join(string: "Hello", toString: "World", withJoiner: ", ")
124 |
125 | // Shorthand external parameter names
126 | func containsCharacter(string string: String, characterToFind: Character) -> Bool {
127 | for character in string.characters {
128 | if character == characterToFind {
129 | return true
130 | }
131 | }
132 |
133 | return false
134 | }
135 |
136 | let containsAVee = containsCharacter(string: "aardvark", characterToFind: "v")
137 |
138 | // Default parameter values
139 | func joinAgain(string s1: String, toString s2: String, withJoiner joiner: String = " ") -> String {
140 | return s1 + joiner + s2
141 | }
142 |
143 | joinAgain(string: "Hello", toString: "World", withJoiner: "-")
144 | joinAgain(string: "Hello", toString: "World")
145 |
146 | // External names for parameters with default values
147 | func joinMissingExternal(s1: String, s2: String, joiner: String = " ") -> String {
148 | return s1 + joiner + s2
149 | }
150 |
151 | joinMissingExternal("Hello", s2: "World", joiner: "-")
152 |
153 | // Variadic parameters
154 | func average(numbers: Double...) -> Double {
155 | var total: Double = 0
156 | for number in numbers {
157 | total += number
158 | }
159 |
160 | return total / Double(numbers.count)
161 | }
162 |
163 | average(1, 2, 3, 4, 5, 6)
164 | average(3, 8.25, 18.75)
165 |
166 | // Constant parameters
167 | func alignRight(string: String, count: Int, pad: Character) -> String {
168 | var string = string
169 | let amountToPad = count - string.characters.count
170 |
171 | if amountToPad < 1 {
172 | return string
173 | }
174 |
175 | let padString = String(pad)
176 |
177 | for _ in 1...amountToPad {
178 | string += padString
179 | }
180 |
181 | return string
182 | }
183 |
184 | let originalString = "hello"
185 | alignRight(originalString, count: 10, pad: "-")
186 | originalString // remains unchanged
187 |
188 | // In-out parameters
189 | func swapTwoInts(inout a: Int, inout b: Int) {
190 | let temporaryA = a
191 | a = b
192 | b = temporaryA
193 | }
194 |
195 | var someInt = 3
196 | var anotherInt = 107
197 | print("(\(someInt), \(anotherInt))")
198 | swapTwoInts(&someInt, b: &anotherInt)
199 | print("(\(someInt), \(anotherInt))")
200 |
201 | //=======================================
202 | // Function Types
203 | //=======================================
204 |
205 | // Examples
206 | func addTwoInts(a: Int, b: Int) -> Int { // Type = (Int, Int) -> Int
207 | return a + b
208 | }
209 |
210 | func multiplyTwoInts(a: Int, b: Int) -> Int { // Type = (Int, Int) -> Int
211 | return a * b
212 | }
213 |
214 | // Using function types (allows you to rename functions)
215 | var mathFunction: (Int, Int) -> Int = addTwoInts
216 | mathFunction(2, 3)
217 | mathFunction = multiplyTwoInts
218 | mathFunction(2, 3)
219 |
220 | // Function types as parameter types
221 | func printMathResult(mathFunction: (Int, Int) -> Int, a: Int, b: Int) {
222 | print("Result: \(mathFunction(a, b))")
223 | }
224 |
225 | printMathResult(addTwoInts, a: 3, b: 5)
226 |
227 | // Function types as return types
228 | func stepForward(input: Int) -> Int {
229 | return input + 1
230 | }
231 |
232 | func stepBackward(input: Int) -> Int {
233 | return input - 1
234 | }
235 |
236 | func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
237 | return backwards ? stepBackward : stepForward
238 | }
239 |
240 | var currentValue = 3
241 | var moveCloserToZero = chooseStepFunction(currentValue > 0)
242 |
243 | print("Counting down to zero:")
244 |
245 | while currentValue != 0 {
246 | print("\(currentValue)...")
247 | currentValue = moveCloserToZero(currentValue)
248 | }
249 |
250 | print("zero!")
251 |
252 | //=======================================
253 | // Nested Functions
254 | //=======================================
255 |
256 | func chooseNestedStepFunction(backwards: Bool) -> (Int) -> Int {
257 | func stepForward(input: Int) -> Int { return input + 1 }
258 | func stepBackward(input: Int) -> Int { return input - 1 }
259 |
260 | return backwards ? stepBackward : stepForward
261 | }
262 |
263 | currentValue = -4
264 | moveCloserToZero = chooseNestedStepFunction(currentValue > 0)
265 |
266 | print("Counting down to zero:")
267 |
268 | while currentValue != 0 {
269 | print("\(currentValue)...")
270 | currentValue = moveCloserToZero(currentValue)
271 | }
272 |
273 | print("zero!")
274 |
--------------------------------------------------------------------------------
/07 - Closures.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/07 - Closures.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/07 - Closures.playground/section-1.swift:
--------------------------------------------------------------------------------
1 |
2 | //=======================================
3 | // Closure Expressions
4 | //=======================================
5 |
6 | // Global Function Closure - Reverse sort an array of names
7 | func backwards(s1: String, s2: String) -> Bool {
8 | return s1 > s2
9 | }
10 |
11 | let names = ["Christian", "Ron", "Jereme", "Eric", "Brad", "Tom"]
12 | var reversed = names.sort(backwards)
13 |
14 | // Closure Expression - Reverse sort an array of names
15 | reversed = names.sort( { (s1: String, s2: String) -> Bool in
16 | return s1 > s2
17 | })
18 |
19 | // Closure Expression on a single line
20 | reversed = names.sort( { (s1: String, s2: String) -> Bool in return s1 > s2 })
21 | reversed
22 |
23 | // Closure Expression with inferred types
24 | reversed = names.sort( { s1, s2 in return s1 > s2 })
25 | reversed
26 |
27 | // Closure Expression with inferred types w/o return
28 | reversed = names.sort( { s1, s2 in s1 > s2 })
29 | reversed
30 |
31 | // Closure Expression with shorthand argument names
32 | reversed = names.sort( { $0 > $1 })
33 | reversed
34 |
35 | // Closure Expression with Operator Functions
36 | reversed = names.sort( >)
37 |
38 | //=======================================
39 | // Trailing Closures
40 | //=======================================
41 |
42 | // Trailing Closure versions of Closure Expressions above
43 | reversed = names.sort() { (s1: String, s2: String) -> Bool in return s1 > s2 }
44 | reversed
45 | reversed = names.sort() { s1, s2 in return s1 > s2 }
46 | reversed
47 | reversed = names.sort() { s1, s2 in s1 > s2 }
48 | reversed
49 | reversed = names.sort() { $0 > $1 }
50 | reversed
51 |
52 | // Trailing Closures with the Array map method
53 | let numbers = [16, 58, 510]
54 | let digitNames = [
55 | 0: "Zero", 1: "One", 2: "Two", 3: "Three", 4: "Four",
56 | 5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
57 | ]
58 |
59 | let strings = numbers.map { number -> String in
60 | var number = number
61 | var output = ""
62 |
63 | while number > 0 {
64 | output = digitNames[number % 10]! + output
65 | number /= 10
66 | }
67 |
68 | return output
69 | }
70 |
71 | strings
72 |
73 | //=======================================
74 | // Capturing Values
75 | //=======================================
76 |
77 | // Function returning a closure that has captured values
78 | func makeIncrementor(forAmount amount: Int) -> Void -> Int {
79 | var runningTotal = 0
80 |
81 | func incrementor() -> Int {
82 | runningTotal += amount
83 | return runningTotal
84 | }
85 |
86 | return incrementor
87 | }
88 |
89 | let incrementByTen = makeIncrementor(forAmount: 10)
90 | let incrementBySeven = makeIncrementor(forAmount: 7)
91 | incrementByTen()
92 | incrementBySeven()
93 | incrementByTen()
94 | incrementBySeven()
95 | incrementByTen()
96 | incrementBySeven()
97 |
98 | // Closures are reference types
99 | let alsoIncrementByTen = incrementByTen // point to same closure
100 | alsoIncrementByTen()
101 | incrementByTen()
102 | alsoIncrementByTen()
103 |
--------------------------------------------------------------------------------
/08 - Enumerations.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/08 - Enumerations.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/08 - Enumerations.playground/section-1.swift:
--------------------------------------------------------------------------------
1 |
2 | //=======================================
3 | // Enumeration Syntax
4 | //=======================================
5 |
6 | // Basic multi-line structure
7 | enum CompassPoint {
8 | case North
9 | case South
10 | case East
11 | case West
12 | }
13 |
14 | // Basic single line structure
15 | enum Planet {
16 | case Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
17 | }
18 |
19 | var directionToHead = CompassPoint.West
20 | directionToHead = .East
21 |
22 | //=======================================
23 | // Matching Enumeration Values
24 | //=======================================
25 |
26 | // Matching enum values with a switch statement that is exhaustive
27 | directionToHead = .South
28 |
29 | switch directionToHead {
30 | case .North:
31 | print("Lots of planets have a north")
32 | case .South:
33 | print("Watch out for penguins")
34 | case .East:
35 | print("Where the sun rises")
36 | case .West:
37 | print("Where the skies are blue")
38 | }
39 |
40 | // Matching enum values with a switch statement that is NOT exhaustive
41 | let somePlanet = Planet.Earth
42 |
43 | switch somePlanet {
44 | case .Earth:
45 | print("Mostly harmless")
46 | default:
47 | print("Not a safe place for humans...yet!")
48 | }
49 |
50 | //=======================================
51 | // Associated Values
52 | //=======================================
53 |
54 | // Enumeration where types are different and contain values
55 | enum Barcode {
56 | case UPCA(Int, Int, Int, Int)
57 | case QRCode(String)
58 | }
59 |
60 | var productBarcode = Barcode.UPCA(8, 85909, 51226, 3)
61 | productBarcode = .QRCode("ABCDEFGHIJKLMNOP")
62 |
63 | // Declare each associated value as a constant
64 | switch productBarcode {
65 | case .UPCA(let numberSystem, let manufacturer, let product, let check):
66 | print("UPC-A: \(numberSystem), \(manufacturer), \(product), \(check)")
67 | case .QRCode(let productCode):
68 | print("QR Code: \(productCode)")
69 | }
70 |
71 | // Declare the entire enumeration member as a constant
72 | switch productBarcode {
73 | case let .UPCA(numberSystem, manufacturer, product, check):
74 | print("UPC-A: \(numberSystem), \(manufacturer), \(product), \(check)")
75 | case let .QRCode(productCode):
76 | print("QR Code: \(productCode)")
77 | }
78 |
79 | //=======================================
80 | // Raw Values
81 | //=======================================
82 |
83 | // Enumeration members that store raw values
84 | enum ASCIIControlCharacter: Character {
85 | case Tab = "\t"
86 | case LineFeed = "\n"
87 | case CarriageReturn = "\r"
88 | }
89 |
90 | // Enumeration of Ints that uses auto-increment for raw values
91 | enum PlanetRaw: Int {
92 | case Mercury = 1, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
93 | }
94 |
95 | let earthsOrder = PlanetRaw.Earth.rawValue
96 | let possiblePlanet = PlanetRaw(rawValue: 7)
97 |
98 | // Enumeration fromRaw method combined with optional binding
99 | let positionToFind = 9
100 |
101 | if let somePlanet = PlanetRaw(rawValue: positionToFind) {
102 | switch somePlanet {
103 | case .Earth:
104 | print("Mostly harmless")
105 | default:
106 | print("Not a safe place for humans...yet!")
107 | }
108 | } else {
109 | print("There isn't a planet at position \(positionToFind)")
110 | }
111 |
--------------------------------------------------------------------------------
/09 - Classes and Structures.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/09 - Classes and Structures.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/09 - Classes and Structures.playground/section-1.swift:
--------------------------------------------------------------------------------
1 |
2 | //=======================================
3 | // Comparing Classes and Structs
4 | //=======================================
5 |
6 | // Basic struct
7 | struct Resolution {
8 | var width = 0
9 | var height = 0
10 | }
11 |
12 | // Basic class
13 | class VideoMode {
14 | var resolution = Resolution()
15 | var interlaced = false
16 | var frameRate = 0.0
17 | var name: String?
18 | }
19 |
20 | // Class and structure instances
21 | let someResolution = Resolution()
22 | let someVideoMode = VideoMode()
23 |
24 | // Accessing properties
25 | someResolution.width
26 | someVideoMode.resolution.width
27 | someVideoMode.resolution.width = 1280
28 | someVideoMode.resolution.width
29 |
30 | // Memberwise initializers for structure types
31 | let vga = Resolution(width: 640, height: 480)
32 |
33 | //=======================================
34 | // Structs & Enums are Value Types
35 | //=======================================
36 |
37 | // Passing around structs created copies since they are value types
38 | var hd = Resolution(width: 1920, height: 1080)
39 | var cinema = hd
40 | cinema.width = 2048
41 | hd.width == cinema.width
42 | hd.width
43 | cinema.width
44 |
45 | // Enums are also value types
46 | enum CompassPoint {
47 | case North, South, East, West
48 | }
49 |
50 | var currentDirection = CompassPoint.West
51 | let rememberedDirection = currentDirection
52 | currentDirection = .East
53 | rememberedDirection == .West
54 |
55 | //=======================================
56 | // Classes are Reference Types
57 | //=======================================
58 |
59 | // Passing around class instances is by reference
60 | let tenEighty = VideoMode()
61 | tenEighty.resolution = hd
62 | tenEighty.interlaced = true
63 | tenEighty.name = "1080i"
64 | tenEighty.frameRate = 25.0
65 |
66 | let alsoTenEighty = tenEighty
67 | alsoTenEighty.frameRate = 30.0
68 |
69 | tenEighty.frameRate == alsoTenEighty.frameRate
70 | tenEighty.frameRate
71 | alsoTenEighty.frameRate
72 |
73 | // Identity Operators (identical to is different than equal to)
74 | tenEighty === alsoTenEighty // a is identical to b - compares pointer memory address
75 | tenEighty !== alsoTenEighty
76 |
77 | //=======================================
78 | // When to use Structs???
79 | //=======================================
80 |
81 | // Use structs when one or more of these conditions apply
82 | // 1) The structure’s primary purpose is to encapsulate a few relatively
83 | // simple data values.
84 | // 2) It is reasonable to expect that the encapsulated values will be copied
85 | // rather than referenced when you assign or pass around an instance of
86 | // that structure.
87 | // 3) Any properties stored by the structure are themselves value types, which
88 | // would also be expected to be copied rather than referenced.
89 | // 4) The structure does not need to inherit properties or behavior from
90 | // another existing type.
91 |
92 | // Examples of good candidates for structs
93 | // 1) The size of a geometric shape, perhaps encapsulating a width property
94 | // and a height property, both of type Double.
95 | // 2) A way to refer to ranges within a series, perhaps encapsulating a start
96 | // property and a length property, both of type Int.
97 | // 3) A point in a 3D coordinate system, perhaps encapsulating x, y and z
98 | // properties, each of type Double.
99 |
--------------------------------------------------------------------------------
/09 - Classes and Structures.playground/timeline.xctimeline:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/10 - Properties.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/10 - Properties.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/10 - Properties.playground/section-1.swift:
--------------------------------------------------------------------------------
1 |
2 | //=======================================
3 | // Stored Properties
4 | //=======================================
5 |
6 | // Constant and variable struct properties
7 | struct FixedLengthRange {
8 | var start: Int
9 | let length: Int
10 | }
11 |
12 | var rangeOfThreeItems = FixedLengthRange(start: 0, length: 3)
13 | rangeOfThreeItems.start = 6
14 |
15 | // Stored properties of constant structure instances
16 | //
17 | // NOTE: You cannot modify variable properties on constant structs b/c they
18 | // are value types. Classes behave differently since they are reference types
19 | let rangeOfFourItems = FixedLengthRange(start: 0, length: 4)
20 | //rangeOfFourItems.start = 4 // reports error b/c properties are also constant
21 |
22 | // Lazy stored properties
23 | class DataImporter {
24 | // Imports data from a file and takes a while to initialize
25 | var fileName = "data.txt"
26 | // Imagine there is importing functionality here...
27 | }
28 |
29 | class DataManager {
30 | lazy var importer = DataImporter()
31 | var data = [String]()
32 | // Imagine there is data management logic here...
33 | }
34 |
35 | let manager = DataManager()
36 | manager.data.append("Some data")
37 | manager.data.append("Some more data")
38 | manager.importer.fileName // importer is not initializer until here
39 |
40 | //=======================================
41 | // Computed Properties
42 | //=======================================
43 |
44 | struct Point {
45 | var x = 0.0, y = 0.0
46 | }
47 |
48 | struct Size {
49 | var width = 0.0, height = 0.0
50 | }
51 |
52 | struct Rect {
53 | var origin = Point()
54 | var size = Size()
55 | var center: Point {
56 | get {
57 | let centerX = origin.x + (size.width / 2.0)
58 | let centerY = origin.y + (size.height / 2.0)
59 | return Point(x: centerX, y: centerY)
60 | }
61 | set(newCenter) {
62 | origin.x = newCenter.x - (size.width / 2.0)
63 | origin.y = newCenter.y - (size.height / 2.0)
64 | }
65 | }
66 | }
67 |
68 | var square = Rect(origin: Point(x: 0.0, y: 0.0), size: Size(width: 10.0, height: 10.0))
69 | let initialSquareCenter = square.center
70 | square.center = Point(x: 15.0, y: 15.0)
71 | square.origin
72 |
73 | // Shorthand setter declaration
74 | struct AlternativeRect {
75 | var origin = Point()
76 | var size = Size()
77 | var center: Point {
78 | get {
79 | let centerX = origin.x + (size.width / 2.0)
80 | let centerY = origin.y + (size.height / 2.0)
81 | return Point(x: centerX, y: centerY)
82 | }
83 | set {
84 | origin.x = newValue.x - (size.width / 2.0)
85 | origin.y = newValue.y - (size.height / 2.0)
86 | }
87 | }
88 | }
89 |
90 | // Read-only computed properties
91 | struct Cuboid {
92 | var width = 0.0, height = 0.0, depth = 0.0
93 | var volume: Double {
94 | return width * height * depth
95 | }
96 | }
97 |
98 | let fourByFiveByTwo = Cuboid(width: 4.0, height: 5.0, depth: 2.0)
99 | fourByFiveByTwo.volume
100 | //fourByFiveByTwo.volume = 60.0 // throws error b/c no setter exists
101 |
102 | // More verbose getter
103 | struct AlernativeCuboid {
104 | var width = 0.0, height = 0.0, depth = 0.0
105 | var volume: Double {
106 | get {
107 | return width * height * depth
108 | }
109 | }
110 | }
111 |
112 | //=======================================
113 | // Property Observers
114 | //=======================================
115 |
116 | class StepCounter {
117 | var totalSteps: Int = 0 {
118 | willSet {
119 | print("About to set totalSteps to \(newValue)")
120 | }
121 | didSet {
122 | print("Added \(totalSteps - oldValue) steps")
123 | }
124 | }
125 | }
126 |
127 | let stepCounter = StepCounter()
128 | stepCounter.totalSteps = 200
129 | stepCounter.totalSteps = 360
130 | stepCounter.totalSteps = 896
131 |
132 | //=======================================
133 | // Type Properties
134 | //=======================================
135 |
136 | // Type property syntax
137 | struct SomeStructure {
138 | static var storedTypeProperty = "Some value"
139 | static var computedTypeProperty: Int {
140 | return 10
141 | }
142 | }
143 |
144 | enum SomeEnumeration {
145 | static var storedTypeProperty = "Some value"
146 | static var computedTypeProperty: Int {
147 | return 20
148 | }
149 | }
150 |
151 | class SomeClass {
152 | class var computedTypeProperty: Int {
153 | return 30
154 | }
155 | }
156 |
157 | // Querying and setting type properties
158 | SomeClass.computedTypeProperty
159 | SomeStructure.storedTypeProperty
160 | SomeStructure.storedTypeProperty = "Another cooler value"
161 | SomeStructure.storedTypeProperty
162 |
163 | // AudioChannel example demonstrating how to use type properties
164 | struct AudioChannel {
165 | static let threshhold = 10
166 | static var maxInputLevelForAllChannels = 0
167 | var currentLevel: Int = 0 {
168 | didSet {
169 | // Cap the current level if above the threshhold
170 | if currentLevel > AudioChannel.threshhold {
171 | currentLevel = AudioChannel.threshhold
172 | }
173 |
174 | // Update the max input level for all channels if necessary
175 | if currentLevel > AudioChannel.maxInputLevelForAllChannels {
176 | AudioChannel.maxInputLevelForAllChannels = currentLevel
177 | }
178 | }
179 | }
180 | }
181 |
182 | var leftChannel = AudioChannel()
183 | var rightChannel = AudioChannel()
184 |
185 | leftChannel.currentLevel = 7
186 | AudioChannel.maxInputLevelForAllChannels
187 |
188 | rightChannel.currentLevel = 11
189 | rightChannel.currentLevel
190 | AudioChannel.maxInputLevelForAllChannels
191 |
--------------------------------------------------------------------------------
/11 - Methods.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/11 - Methods.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/11 - Methods.playground/section-1.swift:
--------------------------------------------------------------------------------
1 |
2 | //=======================================
3 | // Instance Methods
4 | //=======================================
5 |
6 | // Instance methods in a class
7 | class Counter {
8 | var count = 0
9 | func increment() {
10 | count += 1
11 | }
12 | func incrementBy(amount: Int) {
13 | count += amount
14 | }
15 | func reset() {
16 | count = 0
17 | }
18 | }
19 |
20 | let counter = Counter()
21 | counter.increment()
22 | counter.incrementBy(5)
23 | counter.increment()
24 | counter.reset()
25 |
26 | // Logical and external parameter names for methods
27 | class AlternativeCounter {
28 | var count: Int = 0
29 | func incrementBy(amount: Int, numberOfTimes: Int) {
30 | count += amount * numberOfTimes
31 | }
32 |
33 | // The default behavior above treats the method as though you wrote the
34 | // hash symbol (#) in front of all the parameters following the first one
35 |
36 | // func incrementBy(amount: Int, #numberOfTimes: Int) {
37 | // count += amount * numberOfTimes
38 | // }
39 | }
40 |
41 | let altCounter = AlternativeCounter()
42 | altCounter.incrementBy(5, numberOfTimes: 3)
43 |
44 | // The self property - only use self when func parameters names collide with instance property names
45 | struct Point {
46 | var x = 0.0, y = 0.0
47 | func isToTheRightOfX(x: Double) -> Bool {
48 | return self.x > x
49 | }
50 | }
51 |
52 | let somePoint = Point(x: 4.0, y: 5.0)
53 | if somePoint.isToTheRightOfX(1.0) {
54 | print("This point is to the right of the line where x == 1.0")
55 | }
56 |
57 | // Modifying value types from within instance methods
58 | struct MutatingPoint {
59 | var x = 0.0, y = 0.0
60 | mutating func moveByX(deltaX: Double, y deltaY: Double) {
61 | x += deltaX
62 | y += deltaY
63 | }
64 | }
65 |
66 | var mutatingPoint = MutatingPoint(x: 1.0, y: 1.0)
67 | mutatingPoint.moveByX(2.0, y: 3.0)
68 | mutatingPoint
69 |
70 | // Calling mutating method on constant struct throws error
71 | let fixedPoint = MutatingPoint(x: 3.0, y: 3.0)
72 | //fixedPoint.moveByX(2.0, y: 3.0)
73 |
74 | // Assigning to self within a mutating method of a structure
75 | struct MutatingSelfPoint {
76 | var x = 0.0, y = 0.0
77 | mutating func moveByX(deltaX: Double, y deltaY: Double) {
78 | self = MutatingSelfPoint(x: x + deltaX, y: y + deltaY)
79 | }
80 | }
81 |
82 | // Assigning self within a mutating method of an enumeration
83 | enum TriStateSwitch {
84 | case Off, Low, High
85 | mutating func next() {
86 | switch self {
87 | case .Off:
88 | self = Low
89 | case .Low:
90 | self = High
91 | case .High:
92 | self = Off
93 | }
94 | }
95 | }
96 |
97 | var ovenLight = TriStateSwitch.Low
98 | ovenLight.next()
99 | ovenLight == .High
100 | ovenLight.next()
101 | ovenLight == .Off
102 |
103 | //=======================================
104 | // Type Methods
105 | //=======================================
106 |
107 | // Types methods in a structure
108 |
109 | struct LevelTracker {
110 | // Type properties
111 | static var highestUnlockedLevel = 1
112 |
113 | // Type methods
114 | static func unlockLevel(level: Int) {
115 | if level > LevelTracker.highestUnlockedLevel {
116 | LevelTracker.highestUnlockedLevel = level
117 | }
118 | }
119 | static func levelIsUnlocked(level: Int) -> Bool {
120 | return level <= highestUnlockedLevel
121 | }
122 |
123 | // Instance properties
124 | var currentLevel = 1
125 |
126 | // Instance methods
127 | mutating func advanceToLevel(level: Int) -> Bool {
128 | if LevelTracker.levelIsUnlocked(level) {
129 | currentLevel = level
130 | return true
131 | } else {
132 | return false
133 | }
134 | }
135 | }
136 |
137 | class Player {
138 | // Instance properties
139 | var tracker = LevelTracker()
140 | let playerName: String
141 |
142 | // Instance methods
143 | func completedLevel(level: Int) {
144 | LevelTracker.unlockLevel(level + 1)
145 | tracker.advanceToLevel(level + 1)
146 | }
147 | init(name: String) {
148 | playerName = name
149 | }
150 | }
151 |
152 | var player = Player(name: "Argyrios")
153 | player.completedLevel(1)
154 | LevelTracker.highestUnlockedLevel
155 |
156 | player = Player(name: "Beto")
157 |
158 | if player.tracker.advanceToLevel(6) {
159 | print("player is now at level 6")
160 | } else {
161 | print("level 6 has not been unlocked yet")
162 | }
163 |
--------------------------------------------------------------------------------
/12 - Subscripts.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/12 - Subscripts.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/12 - Subscripts.playground/section-1.swift:
--------------------------------------------------------------------------------
1 |
2 | //=======================================
3 | // Subscript Syntax
4 | //=======================================
5 |
6 | // Read-only subscript
7 | struct TimesTable {
8 | let multiplier: Int
9 | subscript(index: Int) -> Int {
10 | return multiplier * index
11 | }
12 | }
13 |
14 | let threeTimesTable = TimesTable(multiplier: 3)
15 | threeTimesTable[6]
16 | threeTimesTable[2]
17 |
18 | // Multi-parameter subscript structure
19 | struct Matrix {
20 | let rows: Int, columns: Int
21 | var grid: [Double]
22 |
23 | init(rows: Int, columns: Int) {
24 | self.rows = rows
25 | self.columns = columns
26 | grid = [Double](count: rows * columns, repeatedValue: 0.0)
27 | }
28 |
29 | func indexIsValidForRow(row: Int, column: Int) -> Bool {
30 | return row >= 0 && row < rows && column >= 0 && column < columns
31 | }
32 |
33 | subscript(row: Int, column: Int) -> Double {
34 | get {
35 | assert(indexIsValidForRow(row, column: column), "Index out of range")
36 | return grid[(row * columns) + column]
37 | }
38 | set {
39 | assert(indexIsValidForRow(row, column: column), "Index out of range")
40 | grid[(row * columns) + column] = newValue
41 | }
42 | }
43 | }
44 |
45 | var matrix = Matrix(rows: 2, columns: 2)
46 | matrix[0, 1] = 1.5
47 | matrix
48 | matrix[1, 0] = 3.2
49 | matrix
50 |
51 | //let someValue = matrix[2, 2] // triggers assert b/c [2, 2] is outside matrix bounds
52 |
--------------------------------------------------------------------------------
/12 - Subscripts.playground/timeline.xctimeline:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/13 - Inheritance.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/13 - Inheritance.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/13 - Inheritance.playground/section-1.swift:
--------------------------------------------------------------------------------
1 |
2 | //=======================================
3 | // Defining a Base Class
4 | //=======================================
5 |
6 | // Base Class
7 | class Vehicle {
8 | var currentSpeed = 0.0
9 | var description: String {
10 | return "traveling at \(currentSpeed) miles per hour"
11 | }
12 |
13 | func makeNoise() {
14 | // do nothing
15 | }
16 | }
17 |
18 | let someVehicle = Vehicle()
19 | someVehicle.description
20 |
21 | //=======================================
22 | // Subclassing
23 | //=======================================
24 |
25 | // Bicycle subclass
26 | class Bicycle: Vehicle {
27 | var hasBasket = false
28 | }
29 |
30 | let bicycle = Bicycle()
31 | bicycle.hasBasket = true
32 | bicycle.currentSpeed = 15.0
33 | bicycle.description
34 |
35 | // Tandem subclass
36 | class Tandem: Bicycle {
37 | var currentNumberOfPassengers = 0
38 | }
39 |
40 | let tandem = Tandem()
41 | tandem.hasBasket = true
42 | tandem.currentNumberOfPassengers = 2
43 | tandem.currentSpeed = 22.0
44 | tandem.description
45 |
46 | //=======================================
47 | // Overridding
48 | //=======================================
49 |
50 | // Overridding methods
51 | class Train: Vehicle {
52 | override func makeNoise() {
53 | print("Choo Choo")
54 | }
55 | }
56 |
57 | let train = Train()
58 | train.makeNoise()
59 |
60 | // Overriding properties
61 | class Car: Vehicle {
62 | var gear = 1
63 | override var description: String {
64 | return super.description + " in gear \(gear)"
65 | }
66 | }
67 |
68 | let car = Car()
69 | car.currentSpeed = 25.0
70 | car.gear = 3
71 | car.description
72 |
73 | // Overridding property observers
74 | class AutomaticCar: Car {
75 | override var currentSpeed: Double {
76 | didSet {
77 | gear = Int(currentSpeed / 10.0) + 1
78 | }
79 | }
80 | }
81 |
82 | let automatic = AutomaticCar()
83 | automatic.currentSpeed = 35.0
84 | automatic.description
85 |
86 | // Preventing overrides for entire class
87 | final class MuscleCar: Car {
88 | var color: String?
89 | }
90 |
91 | //class Camaro: MuscleCar {} // compiler error since MuscleCar is final
92 |
93 | // Preventing overrides for methods, properties, or subscripts
94 | class ManualCar: Car {
95 | final var tireWidth: Double = 0.0
96 | final override func makeNoise() {
97 | print("Waahhh waahhh")
98 | }
99 | }
100 |
101 | class Ferari: ManualCar {
102 | // override var tireWidth: Double {} // compiler error since tireWidth is final
103 | }
104 |
--------------------------------------------------------------------------------
/14 - Initialization.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/14 - Initialization.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/14 - Initialization.playground/section-1.swift:
--------------------------------------------------------------------------------
1 |
2 | //================================================================
3 | // Setting Initial Values for Stored Properties
4 | //================================================================
5 |
6 | // Initializers
7 | struct Fahrenheit {
8 | var temperature: Double
9 |
10 | init() {
11 | temperature = 32.0
12 | }
13 | }
14 |
15 | var f = Fahrenheit()
16 | f.temperature
17 |
18 | // Default property values
19 | struct ConciseFahrenheit {
20 | var temperature = 32.0
21 | }
22 |
23 | //================================================================
24 | // Customizing Initialization
25 | //================================================================
26 |
27 | // Initialization parameters
28 | struct Celsius {
29 | var temperatureInCelsius: Double
30 |
31 | init(fromFahrenheit fahrenheit: Double) {
32 | temperatureInCelsius = (fahrenheit - 32.0) / 1.8
33 | }
34 | init(fromKelvin kelvin: Double) {
35 | temperatureInCelsius = kelvin - 273.15
36 | }
37 | }
38 |
39 | let boilingPointOfWater = Celsius(fromFahrenheit: 212.0)
40 | boilingPointOfWater.temperatureInCelsius
41 |
42 | let freezingPointOfWater = Celsius(fromKelvin: 273.15)
43 | freezingPointOfWater.temperatureInCelsius
44 |
45 | // Local and external parameter names
46 | struct Color {
47 | let red, green, blue: Double
48 |
49 | init(red: Double, green: Double, blue: Double) {
50 | self.red = red
51 | self.green = green
52 | self.blue = blue
53 | }
54 |
55 | init(white: Double) {
56 | self.red = white
57 | self.green = white
58 | self.blue = white
59 | }
60 | }
61 |
62 | let magenta = Color(red: 1.0, green: 0.0, blue: 1.0)
63 | let halfGray = Color(white: 0.5)
64 | //let veryGreen = Color(0.0, 1.0, 0.0) // compiler error - external names required
65 |
66 | // Initializer parameters without external names
67 | struct Celsius2 {
68 | var temperatureInCelsius: Double
69 |
70 | init(_ celsius: Double) { // _ allows you to remove external parameter requirement
71 | temperatureInCelsius = celsius
72 | }
73 |
74 | init(fromFahrenheit fahrenheit: Double) {
75 | temperatureInCelsius = (fahrenheit - 32.0) / 1.8
76 | }
77 |
78 | init(fromKelvin kelvin: Double) {
79 | temperatureInCelsius = kelvin - 273.15
80 | }
81 | }
82 |
83 | let bodyTemperature = Celsius2(37.0)
84 |
85 | // Optional property types
86 | class SurveyQuestion {
87 | var text: String
88 | var response: String?
89 |
90 | init(text: String) {
91 | self.text = text
92 | }
93 |
94 | func ask() {
95 | print(text)
96 | }
97 | }
98 |
99 | let cheeseQuestion = SurveyQuestion(text: "Do you like cheese?")
100 | cheeseQuestion.ask()
101 | cheeseQuestion.response
102 | cheeseQuestion.response = "Yes, I do like cheese."
103 | cheeseQuestion.response!
104 |
105 | // Modifying constant properties during initialization
106 | class SurveyQuestion2 {
107 | let text: String
108 | var response: String?
109 |
110 | init(text: String) {
111 | self.text = text
112 | }
113 |
114 | func ask() {
115 | print(text)
116 | }
117 | }
118 |
119 | let beetsQuestion = SurveyQuestion2(text: "How about beets?")
120 | beetsQuestion.ask()
121 | //beetsQuestion.text = "How about turnips?" // compiler error - cannot assign text
122 | beetsQuestion.response = "I also like beets."
123 | beetsQuestion.response!
124 |
125 | //================================================================
126 | // Default Initializers
127 | //================================================================
128 |
129 | // Default initializer example
130 | class ShoppingListIngredient {
131 | var name: String?
132 | var quantity = 1
133 | var purchased = false
134 | }
135 |
136 | var ingredient = ShoppingListIngredient()
137 |
138 | // Memberwise initializers for structure types
139 | struct Sizer {
140 | var width = 0.0, height = 0.0
141 | }
142 |
143 | let twoByTwo = Sizer(width: 2.0, height: 2.0)
144 |
145 | //================================================================
146 | // Initializer Delegation for Value Types
147 | //================================================================
148 |
149 | struct Point {
150 | var x = 0.0, y = 0.0
151 | }
152 | struct Size {
153 | var width = 0.0, height = 0.0
154 | }
155 | struct Rect {
156 | var origin = Point()
157 | var size = Size()
158 |
159 | init() {}
160 | init(origin: Point, size: Size) {
161 | self.origin = origin
162 | self.size = size
163 | }
164 | init(center: Point, size: Size) {
165 | let originX = center.x - (size.width / 2.0)
166 | let originY = center.y - (size.height / 2.0)
167 | self.init(origin: Point(x: originX, y: originY), size: size)
168 | }
169 | }
170 |
171 | let basicRect = Rect()
172 | let originRect = Rect(origin: Point(x: 2.0, y: 2.0), size: Size(width: 5.0, height: 5.0))
173 | let centerRect = Rect(center: Point(x: 4.0, y: 4.0), size: Size(width: 3.0, height: 3.0))
174 |
175 | //================================================================
176 | // Class Inheritance and Initialization
177 | //================================================================
178 |
179 | // Designated initializers and convenience intiailizers
180 | class Vehicle {
181 | var numberOfWheels = 0
182 | var description: String {
183 | return "\(numberOfWheels) wheel(s)"
184 | }
185 | }
186 |
187 | class Bicycle: Vehicle {
188 | override init() {
189 | super.init()
190 | numberOfWheels = 2
191 | }
192 | }
193 |
194 | let vehicle = Vehicle()
195 | vehicle.description
196 |
197 | let bicycle = Bicycle()
198 | bicycle.description
199 |
200 | // Designated and Convenience Initializers in Action
201 | class Food {
202 | var name: String
203 |
204 | init(name: String) {
205 | print("Food init:name")
206 | self.name = name
207 | }
208 |
209 | convenience init() {
210 | print("Food convenience init")
211 | self.init(name: "[Unnamed]")
212 | }
213 | }
214 |
215 | class RecipeIntegredient: Food {
216 | var quantity: Int
217 |
218 | init(name: String, quantity: Int) {
219 | print("RecipeIntegredient init:name:quantity")
220 | self.quantity = quantity
221 | super.init(name: name)
222 | }
223 |
224 | override convenience init(name: String) {
225 | print("RecipeIntegredient convenience init:name")
226 | self.init(name: name, quantity: 1)
227 | }
228 | }
229 |
230 | class ShoppingListItem: RecipeIntegredient {
231 | var purchased = false
232 | var description: String {
233 | var output = "\(quantity) x \(name)"
234 | output += purchased ? " ✔" : " ✘"
235 | return output
236 | }
237 | }
238 |
239 | let namedMeat = Food(name: "Bacon")
240 | let mysteryMeat = Food()
241 |
242 | let oneMysteryItem = RecipeIntegredient()
243 | let oneBacon = RecipeIntegredient(name: "Bacon")
244 | let sixEggs = RecipeIntegredient(name: "Eggs", quantity: 6)
245 |
246 | var breakfastList = [
247 | ShoppingListItem(),
248 | ShoppingListItem(name: "Bacon"),
249 | ShoppingListItem(name: "Eggs", quantity: 6)
250 | ]
251 |
252 | breakfastList[0].name = "Orange Juice"
253 | breakfastList[0].purchased = true
254 |
255 | for item in breakfastList {
256 | print(item.description)
257 | }
258 |
259 | // Required initializers
260 | class SomeClass {
261 | required init() {
262 | // init implementation goes here
263 | }
264 | }
265 |
266 | class SomeSubclass: SomeClass {
267 | required init() {
268 | // subclass implementation goes here
269 | }
270 | }
271 |
272 | //================================================================
273 | // Setting a Default Property Value with a Closure or Function
274 | //================================================================
275 |
276 | struct Checkerboard {
277 | let boardColors: [Bool] = {
278 | var temporaryBoard = [Bool]()
279 | var isBlack = false
280 |
281 | for i in 1...10 {
282 | for j in 1...10 {
283 | temporaryBoard.append(isBlack)
284 | isBlack = !isBlack
285 | }
286 | isBlack = !isBlack
287 | }
288 | return temporaryBoard
289 | }()
290 |
291 | func squareIsBlackAtRow(row: Int, column: Int) -> Bool {
292 | return boardColors[(row * 10) + column]
293 | }
294 | }
295 |
296 | let board = Checkerboard()
297 | board.squareIsBlackAtRow(0, column: 1)
298 | board.squareIsBlackAtRow(9, column: 9)
299 |
--------------------------------------------------------------------------------
/15 - Deinitialization/15 - Deinitialization.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 4C3A432519B26E100010994E /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3A432419B26E100010994E /* main.swift */; };
11 | /* End PBXBuildFile section */
12 |
13 | /* Begin PBXCopyFilesBuildPhase section */
14 | 4C3A431F19B26E100010994E /* CopyFiles */ = {
15 | isa = PBXCopyFilesBuildPhase;
16 | buildActionMask = 2147483647;
17 | dstPath = /usr/share/man/man1/;
18 | dstSubfolderSpec = 0;
19 | files = (
20 | );
21 | runOnlyForDeploymentPostprocessing = 1;
22 | };
23 | /* End PBXCopyFilesBuildPhase section */
24 |
25 | /* Begin PBXFileReference section */
26 | 4C3A432119B26E100010994E /* 15 - Deinitialization */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "15 - Deinitialization"; sourceTree = BUILT_PRODUCTS_DIR; };
27 | 4C3A432419B26E100010994E /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; };
28 | /* End PBXFileReference section */
29 |
30 | /* Begin PBXFrameworksBuildPhase section */
31 | 4C3A431E19B26E100010994E /* Frameworks */ = {
32 | isa = PBXFrameworksBuildPhase;
33 | buildActionMask = 2147483647;
34 | files = (
35 | );
36 | runOnlyForDeploymentPostprocessing = 0;
37 | };
38 | /* End PBXFrameworksBuildPhase section */
39 |
40 | /* Begin PBXGroup section */
41 | 4C3A431819B26E100010994E = {
42 | isa = PBXGroup;
43 | children = (
44 | 4C3A432319B26E100010994E /* 15 - Deinitialization */,
45 | 4C3A432219B26E100010994E /* Products */,
46 | );
47 | sourceTree = "";
48 | };
49 | 4C3A432219B26E100010994E /* Products */ = {
50 | isa = PBXGroup;
51 | children = (
52 | 4C3A432119B26E100010994E /* 15 - Deinitialization */,
53 | );
54 | name = Products;
55 | sourceTree = "";
56 | };
57 | 4C3A432319B26E100010994E /* 15 - Deinitialization */ = {
58 | isa = PBXGroup;
59 | children = (
60 | 4C3A432419B26E100010994E /* main.swift */,
61 | );
62 | path = "15 - Deinitialization";
63 | sourceTree = "";
64 | };
65 | /* End PBXGroup section */
66 |
67 | /* Begin PBXNativeTarget section */
68 | 4C3A432019B26E100010994E /* 15 - Deinitialization */ = {
69 | isa = PBXNativeTarget;
70 | buildConfigurationList = 4C3A432819B26E100010994E /* Build configuration list for PBXNativeTarget "15 - Deinitialization" */;
71 | buildPhases = (
72 | 4C3A431D19B26E100010994E /* Sources */,
73 | 4C3A431E19B26E100010994E /* Frameworks */,
74 | 4C3A431F19B26E100010994E /* CopyFiles */,
75 | );
76 | buildRules = (
77 | );
78 | dependencies = (
79 | );
80 | name = "15 - Deinitialization";
81 | productName = "15 - Deinitialization";
82 | productReference = 4C3A432119B26E100010994E /* 15 - Deinitialization */;
83 | productType = "com.apple.product-type.tool";
84 | };
85 | /* End PBXNativeTarget section */
86 |
87 | /* Begin PBXProject section */
88 | 4C3A431919B26E100010994E /* Project object */ = {
89 | isa = PBXProject;
90 | attributes = {
91 | LastSwiftMigration = 0730;
92 | LastSwiftUpdateCheck = 0730;
93 | LastUpgradeCheck = 0730;
94 | ORGANIZATIONNAME = Noondev;
95 | TargetAttributes = {
96 | 4C3A432019B26E100010994E = {
97 | CreatedOnToolsVersion = 6.0;
98 | };
99 | };
100 | };
101 | buildConfigurationList = 4C3A431C19B26E100010994E /* Build configuration list for PBXProject "15 - Deinitialization" */;
102 | compatibilityVersion = "Xcode 3.2";
103 | developmentRegion = English;
104 | hasScannedForEncodings = 0;
105 | knownRegions = (
106 | en,
107 | );
108 | mainGroup = 4C3A431819B26E100010994E;
109 | productRefGroup = 4C3A432219B26E100010994E /* Products */;
110 | projectDirPath = "";
111 | projectRoot = "";
112 | targets = (
113 | 4C3A432019B26E100010994E /* 15 - Deinitialization */,
114 | );
115 | };
116 | /* End PBXProject section */
117 |
118 | /* Begin PBXSourcesBuildPhase section */
119 | 4C3A431D19B26E100010994E /* Sources */ = {
120 | isa = PBXSourcesBuildPhase;
121 | buildActionMask = 2147483647;
122 | files = (
123 | 4C3A432519B26E100010994E /* main.swift in Sources */,
124 | );
125 | runOnlyForDeploymentPostprocessing = 0;
126 | };
127 | /* End PBXSourcesBuildPhase section */
128 |
129 | /* Begin XCBuildConfiguration section */
130 | 4C3A432619B26E100010994E /* Debug */ = {
131 | isa = XCBuildConfiguration;
132 | buildSettings = {
133 | ALWAYS_SEARCH_USER_PATHS = NO;
134 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
135 | CLANG_CXX_LIBRARY = "libc++";
136 | CLANG_ENABLE_MODULES = YES;
137 | CLANG_ENABLE_OBJC_ARC = YES;
138 | CLANG_WARN_BOOL_CONVERSION = YES;
139 | CLANG_WARN_CONSTANT_CONVERSION = YES;
140 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
141 | CLANG_WARN_EMPTY_BODY = YES;
142 | CLANG_WARN_ENUM_CONVERSION = YES;
143 | CLANG_WARN_INT_CONVERSION = YES;
144 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
145 | CLANG_WARN_UNREACHABLE_CODE = YES;
146 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
147 | COPY_PHASE_STRIP = NO;
148 | ENABLE_STRICT_OBJC_MSGSEND = YES;
149 | ENABLE_TESTABILITY = YES;
150 | GCC_C_LANGUAGE_STANDARD = gnu99;
151 | GCC_DYNAMIC_NO_PIC = NO;
152 | GCC_OPTIMIZATION_LEVEL = 0;
153 | GCC_PREPROCESSOR_DEFINITIONS = (
154 | "DEBUG=1",
155 | "$(inherited)",
156 | );
157 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
158 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
159 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
160 | GCC_WARN_UNDECLARED_SELECTOR = YES;
161 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
162 | GCC_WARN_UNUSED_FUNCTION = YES;
163 | GCC_WARN_UNUSED_VARIABLE = YES;
164 | MACOSX_DEPLOYMENT_TARGET = 10.9;
165 | MTL_ENABLE_DEBUG_INFO = YES;
166 | ONLY_ACTIVE_ARCH = YES;
167 | SDKROOT = macosx;
168 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
169 | };
170 | name = Debug;
171 | };
172 | 4C3A432719B26E100010994E /* Release */ = {
173 | isa = XCBuildConfiguration;
174 | buildSettings = {
175 | ALWAYS_SEARCH_USER_PATHS = NO;
176 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
177 | CLANG_CXX_LIBRARY = "libc++";
178 | CLANG_ENABLE_MODULES = YES;
179 | CLANG_ENABLE_OBJC_ARC = YES;
180 | CLANG_WARN_BOOL_CONVERSION = YES;
181 | CLANG_WARN_CONSTANT_CONVERSION = YES;
182 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
183 | CLANG_WARN_EMPTY_BODY = YES;
184 | CLANG_WARN_ENUM_CONVERSION = YES;
185 | CLANG_WARN_INT_CONVERSION = YES;
186 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
187 | CLANG_WARN_UNREACHABLE_CODE = YES;
188 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
189 | COPY_PHASE_STRIP = YES;
190 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
191 | ENABLE_NS_ASSERTIONS = NO;
192 | ENABLE_STRICT_OBJC_MSGSEND = YES;
193 | GCC_C_LANGUAGE_STANDARD = gnu99;
194 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
195 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
196 | GCC_WARN_UNDECLARED_SELECTOR = YES;
197 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
198 | GCC_WARN_UNUSED_FUNCTION = YES;
199 | GCC_WARN_UNUSED_VARIABLE = YES;
200 | MACOSX_DEPLOYMENT_TARGET = 10.9;
201 | MTL_ENABLE_DEBUG_INFO = NO;
202 | SDKROOT = macosx;
203 | };
204 | name = Release;
205 | };
206 | 4C3A432919B26E100010994E /* Debug */ = {
207 | isa = XCBuildConfiguration;
208 | buildSettings = {
209 | PRODUCT_NAME = "$(TARGET_NAME)";
210 | };
211 | name = Debug;
212 | };
213 | 4C3A432A19B26E100010994E /* Release */ = {
214 | isa = XCBuildConfiguration;
215 | buildSettings = {
216 | PRODUCT_NAME = "$(TARGET_NAME)";
217 | };
218 | name = Release;
219 | };
220 | /* End XCBuildConfiguration section */
221 |
222 | /* Begin XCConfigurationList section */
223 | 4C3A431C19B26E100010994E /* Build configuration list for PBXProject "15 - Deinitialization" */ = {
224 | isa = XCConfigurationList;
225 | buildConfigurations = (
226 | 4C3A432619B26E100010994E /* Debug */,
227 | 4C3A432719B26E100010994E /* Release */,
228 | );
229 | defaultConfigurationIsVisible = 0;
230 | defaultConfigurationName = Release;
231 | };
232 | 4C3A432819B26E100010994E /* Build configuration list for PBXNativeTarget "15 - Deinitialization" */ = {
233 | isa = XCConfigurationList;
234 | buildConfigurations = (
235 | 4C3A432919B26E100010994E /* Debug */,
236 | 4C3A432A19B26E100010994E /* Release */,
237 | );
238 | defaultConfigurationIsVisible = 0;
239 | defaultConfigurationName = Release;
240 | };
241 | /* End XCConfigurationList section */
242 | };
243 | rootObject = 4C3A431919B26E100010994E /* Project object */;
244 | }
245 |
--------------------------------------------------------------------------------
/15 - Deinitialization/15 - Deinitialization.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/15 - Deinitialization/15 - Deinitialization/main.swift:
--------------------------------------------------------------------------------
1 | //
2 | // main.swift
3 | // 15 - Deinitialization
4 | //
5 | // Created by Christian Noon on 8/30/14.
6 | // Copyright (c) 2014 Noondev. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | //======================================
12 | // Deinitializers in Action
13 | //======================================
14 |
15 | struct Bank {
16 | static var coinsInBank = 10_000
17 |
18 | static func vendCoins(numberOfCoinsToVend: Int) -> Int {
19 | var numberOfCoinsToVend = numberOfCoinsToVend
20 | numberOfCoinsToVend = min(numberOfCoinsToVend, coinsInBank)
21 | coinsInBank -= numberOfCoinsToVend
22 |
23 | return numberOfCoinsToVend
24 | }
25 |
26 | static func receiveCoins(coins: Int) {
27 | coinsInBank += coins
28 | }
29 | }
30 |
31 | class Player {
32 | var coinsInPurse: Int
33 |
34 | init(coins: Int) {
35 | coinsInPurse = Bank.vendCoins(coins)
36 | }
37 | deinit {
38 | Bank.receiveCoins(coinsInPurse)
39 | }
40 |
41 | func winCoins(coins: Int) {
42 | coinsInPurse += Bank.vendCoins(coins)
43 | }
44 | }
45 |
46 | var playerOne: Player? = Player(coins: 100)
47 | print("A new player has joined the game with \(playerOne!.coinsInPurse) coins")
48 | print("There are now \(Bank.coinsInBank) coins left in the bank")
49 | print("")
50 |
51 | playerOne!.winCoins(2_000)
52 | print("PlayerOne won 2000 coins & now has \(playerOne!.coinsInPurse) coins")
53 | print("The bank now only has \(Bank.coinsInBank) coins left")
54 | print("")
55 |
56 | playerOne = nil
57 | print("PlayerOne has left the game")
58 | print("The bank now has \(Bank.coinsInBank) coins")
59 | print("")
60 |
--------------------------------------------------------------------------------
/16 - Automatic Reference Counting/16 - Automatic Reference Counting.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 4C926FC419B2606D00C65226 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C926FC319B2606D00C65226 /* main.swift */; };
11 | /* End PBXBuildFile section */
12 |
13 | /* Begin PBXCopyFilesBuildPhase section */
14 | 4C926FBE19B2606D00C65226 /* CopyFiles */ = {
15 | isa = PBXCopyFilesBuildPhase;
16 | buildActionMask = 2147483647;
17 | dstPath = /usr/share/man/man1/;
18 | dstSubfolderSpec = 0;
19 | files = (
20 | );
21 | runOnlyForDeploymentPostprocessing = 1;
22 | };
23 | /* End PBXCopyFilesBuildPhase section */
24 |
25 | /* Begin PBXFileReference section */
26 | 4C926FC019B2606D00C65226 /* 16 - Automatic Reference Counting */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "16 - Automatic Reference Counting"; sourceTree = BUILT_PRODUCTS_DIR; };
27 | 4C926FC319B2606D00C65226 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; };
28 | /* End PBXFileReference section */
29 |
30 | /* Begin PBXFrameworksBuildPhase section */
31 | 4C926FBD19B2606D00C65226 /* Frameworks */ = {
32 | isa = PBXFrameworksBuildPhase;
33 | buildActionMask = 2147483647;
34 | files = (
35 | );
36 | runOnlyForDeploymentPostprocessing = 0;
37 | };
38 | /* End PBXFrameworksBuildPhase section */
39 |
40 | /* Begin PBXGroup section */
41 | 4C926FB719B2606D00C65226 = {
42 | isa = PBXGroup;
43 | children = (
44 | 4C926FC219B2606D00C65226 /* 16 - Automatic Reference Counting */,
45 | 4C926FC119B2606D00C65226 /* Products */,
46 | );
47 | sourceTree = "";
48 | };
49 | 4C926FC119B2606D00C65226 /* Products */ = {
50 | isa = PBXGroup;
51 | children = (
52 | 4C926FC019B2606D00C65226 /* 16 - Automatic Reference Counting */,
53 | );
54 | name = Products;
55 | sourceTree = "";
56 | };
57 | 4C926FC219B2606D00C65226 /* 16 - Automatic Reference Counting */ = {
58 | isa = PBXGroup;
59 | children = (
60 | 4C926FC319B2606D00C65226 /* main.swift */,
61 | );
62 | path = "16 - Automatic Reference Counting";
63 | sourceTree = "";
64 | };
65 | /* End PBXGroup section */
66 |
67 | /* Begin PBXNativeTarget section */
68 | 4C926FBF19B2606D00C65226 /* 16 - Automatic Reference Counting */ = {
69 | isa = PBXNativeTarget;
70 | buildConfigurationList = 4C926FC719B2606D00C65226 /* Build configuration list for PBXNativeTarget "16 - Automatic Reference Counting" */;
71 | buildPhases = (
72 | 4C926FBC19B2606D00C65226 /* Sources */,
73 | 4C926FBD19B2606D00C65226 /* Frameworks */,
74 | 4C926FBE19B2606D00C65226 /* CopyFiles */,
75 | );
76 | buildRules = (
77 | );
78 | dependencies = (
79 | );
80 | name = "16 - Automatic Reference Counting";
81 | productName = "16 - Automatic Reference Counting";
82 | productReference = 4C926FC019B2606D00C65226 /* 16 - Automatic Reference Counting */;
83 | productType = "com.apple.product-type.tool";
84 | };
85 | /* End PBXNativeTarget section */
86 |
87 | /* Begin PBXProject section */
88 | 4C926FB819B2606D00C65226 /* Project object */ = {
89 | isa = PBXProject;
90 | attributes = {
91 | LastSwiftMigration = 0730;
92 | LastSwiftUpdateCheck = 0730;
93 | LastUpgradeCheck = 0730;
94 | ORGANIZATIONNAME = Noondev;
95 | TargetAttributes = {
96 | 4C926FBF19B2606D00C65226 = {
97 | CreatedOnToolsVersion = 6.0;
98 | };
99 | };
100 | };
101 | buildConfigurationList = 4C926FBB19B2606D00C65226 /* Build configuration list for PBXProject "16 - Automatic Reference Counting" */;
102 | compatibilityVersion = "Xcode 3.2";
103 | developmentRegion = English;
104 | hasScannedForEncodings = 0;
105 | knownRegions = (
106 | en,
107 | );
108 | mainGroup = 4C926FB719B2606D00C65226;
109 | productRefGroup = 4C926FC119B2606D00C65226 /* Products */;
110 | projectDirPath = "";
111 | projectRoot = "";
112 | targets = (
113 | 4C926FBF19B2606D00C65226 /* 16 - Automatic Reference Counting */,
114 | );
115 | };
116 | /* End PBXProject section */
117 |
118 | /* Begin PBXSourcesBuildPhase section */
119 | 4C926FBC19B2606D00C65226 /* Sources */ = {
120 | isa = PBXSourcesBuildPhase;
121 | buildActionMask = 2147483647;
122 | files = (
123 | 4C926FC419B2606D00C65226 /* main.swift in Sources */,
124 | );
125 | runOnlyForDeploymentPostprocessing = 0;
126 | };
127 | /* End PBXSourcesBuildPhase section */
128 |
129 | /* Begin XCBuildConfiguration section */
130 | 4C926FC519B2606D00C65226 /* Debug */ = {
131 | isa = XCBuildConfiguration;
132 | buildSettings = {
133 | ALWAYS_SEARCH_USER_PATHS = NO;
134 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
135 | CLANG_CXX_LIBRARY = "libc++";
136 | CLANG_ENABLE_MODULES = YES;
137 | CLANG_ENABLE_OBJC_ARC = YES;
138 | CLANG_WARN_BOOL_CONVERSION = YES;
139 | CLANG_WARN_CONSTANT_CONVERSION = YES;
140 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
141 | CLANG_WARN_EMPTY_BODY = YES;
142 | CLANG_WARN_ENUM_CONVERSION = YES;
143 | CLANG_WARN_INT_CONVERSION = YES;
144 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
145 | CLANG_WARN_UNREACHABLE_CODE = YES;
146 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
147 | COPY_PHASE_STRIP = NO;
148 | ENABLE_STRICT_OBJC_MSGSEND = YES;
149 | ENABLE_TESTABILITY = YES;
150 | GCC_C_LANGUAGE_STANDARD = gnu99;
151 | GCC_DYNAMIC_NO_PIC = NO;
152 | GCC_OPTIMIZATION_LEVEL = 0;
153 | GCC_PREPROCESSOR_DEFINITIONS = (
154 | "DEBUG=1",
155 | "$(inherited)",
156 | );
157 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
158 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
159 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
160 | GCC_WARN_UNDECLARED_SELECTOR = YES;
161 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
162 | GCC_WARN_UNUSED_FUNCTION = YES;
163 | GCC_WARN_UNUSED_VARIABLE = YES;
164 | MACOSX_DEPLOYMENT_TARGET = 10.9;
165 | MTL_ENABLE_DEBUG_INFO = YES;
166 | ONLY_ACTIVE_ARCH = YES;
167 | SDKROOT = macosx;
168 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
169 | };
170 | name = Debug;
171 | };
172 | 4C926FC619B2606D00C65226 /* Release */ = {
173 | isa = XCBuildConfiguration;
174 | buildSettings = {
175 | ALWAYS_SEARCH_USER_PATHS = NO;
176 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
177 | CLANG_CXX_LIBRARY = "libc++";
178 | CLANG_ENABLE_MODULES = YES;
179 | CLANG_ENABLE_OBJC_ARC = YES;
180 | CLANG_WARN_BOOL_CONVERSION = YES;
181 | CLANG_WARN_CONSTANT_CONVERSION = YES;
182 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
183 | CLANG_WARN_EMPTY_BODY = YES;
184 | CLANG_WARN_ENUM_CONVERSION = YES;
185 | CLANG_WARN_INT_CONVERSION = YES;
186 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
187 | CLANG_WARN_UNREACHABLE_CODE = YES;
188 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
189 | COPY_PHASE_STRIP = YES;
190 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
191 | ENABLE_NS_ASSERTIONS = NO;
192 | ENABLE_STRICT_OBJC_MSGSEND = YES;
193 | GCC_C_LANGUAGE_STANDARD = gnu99;
194 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
195 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
196 | GCC_WARN_UNDECLARED_SELECTOR = YES;
197 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
198 | GCC_WARN_UNUSED_FUNCTION = YES;
199 | GCC_WARN_UNUSED_VARIABLE = YES;
200 | MACOSX_DEPLOYMENT_TARGET = 10.9;
201 | MTL_ENABLE_DEBUG_INFO = NO;
202 | SDKROOT = macosx;
203 | };
204 | name = Release;
205 | };
206 | 4C926FC819B2606D00C65226 /* Debug */ = {
207 | isa = XCBuildConfiguration;
208 | buildSettings = {
209 | PRODUCT_NAME = "$(TARGET_NAME)";
210 | };
211 | name = Debug;
212 | };
213 | 4C926FC919B2606D00C65226 /* Release */ = {
214 | isa = XCBuildConfiguration;
215 | buildSettings = {
216 | PRODUCT_NAME = "$(TARGET_NAME)";
217 | };
218 | name = Release;
219 | };
220 | /* End XCBuildConfiguration section */
221 |
222 | /* Begin XCConfigurationList section */
223 | 4C926FBB19B2606D00C65226 /* Build configuration list for PBXProject "16 - Automatic Reference Counting" */ = {
224 | isa = XCConfigurationList;
225 | buildConfigurations = (
226 | 4C926FC519B2606D00C65226 /* Debug */,
227 | 4C926FC619B2606D00C65226 /* Release */,
228 | );
229 | defaultConfigurationIsVisible = 0;
230 | defaultConfigurationName = Release;
231 | };
232 | 4C926FC719B2606D00C65226 /* Build configuration list for PBXNativeTarget "16 - Automatic Reference Counting" */ = {
233 | isa = XCConfigurationList;
234 | buildConfigurations = (
235 | 4C926FC819B2606D00C65226 /* Debug */,
236 | 4C926FC919B2606D00C65226 /* Release */,
237 | );
238 | defaultConfigurationIsVisible = 0;
239 | defaultConfigurationName = Release;
240 | };
241 | /* End XCConfigurationList section */
242 | };
243 | rootObject = 4C926FB819B2606D00C65226 /* Project object */;
244 | }
245 |
--------------------------------------------------------------------------------
/16 - Automatic Reference Counting/16 - Automatic Reference Counting.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/16 - Automatic Reference Counting/16 - Automatic Reference Counting/main.swift:
--------------------------------------------------------------------------------
1 | //
2 | // main.swift
3 | // 16 - Automatic Reference Counting
4 | //
5 | // Created by Christian Noon on 8/30/14.
6 | // Copyright (c) 2014 Noondev. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | //=======================================================================
12 | // ARC in Action
13 | //=======================================================================
14 |
15 | print("==== ARC in Action ====")
16 |
17 | class Actor {
18 | let name: String
19 |
20 | init(name: String) {
21 | self.name = name
22 | print("\(name) is being initialized")
23 | }
24 |
25 | deinit {
26 | print("\(name) is being deinitialized")
27 | }
28 | }
29 |
30 | var reference1: Actor?
31 | var reference2: Actor?
32 | var reference3: Actor?
33 |
34 | reference1 = Actor(name: "Chris Pratt")
35 | reference2 = reference1
36 | reference3 = reference1
37 |
38 | reference1 = nil
39 | print("nil'd out reference1")
40 | reference2 = nil
41 | print("nil'd out reference2")
42 | reference3 = nil
43 | print("nil'd out reference3")
44 |
45 | //=======================================================================
46 | // Strong Reference Cycles Between Class Instances
47 | //=======================================================================
48 |
49 | print("\n==== Strong Reference Cycles Between Class Instances ====")
50 |
51 | // Strong Reference Cycle Example
52 | class Person {
53 | let name: String
54 | var apartment: Apartment?
55 |
56 | init(name: String) {
57 | self.name = name
58 | }
59 |
60 | deinit {
61 | print("\(name) is being deinitialized")
62 | }
63 | }
64 |
65 | class Apartment {
66 | let number: Int
67 | var tenant: Person?
68 |
69 | init(number: Int) {
70 | self.number = number
71 | }
72 |
73 | deinit {
74 | print("Apartment #\(number)")
75 | }
76 | }
77 |
78 | var john: Person?
79 | var number73: Apartment?
80 |
81 | john = Person(name: "John Appleseed")
82 | number73 = Apartment(number: 73)
83 |
84 | john!.apartment = number73
85 | number73!.tenant = john
86 |
87 | john = nil
88 | number73 = nil
89 | print("john and number73 do NOT get deinitialized due to strong reference cycle!!!")
90 |
91 | //=======================================================================
92 | // Resolving Strong Reference Cycles Between Class Instances
93 | //=======================================================================
94 |
95 | print("\n==== Resolving Strong Reference Cycles Between Class Instances ====")
96 |
97 | // Weak references example
98 | class Person2 {
99 | let name: String
100 | var apartment: Apartment2?
101 |
102 | init(name: String) {
103 | self.name = name
104 | }
105 |
106 | deinit {
107 | print("\(name) is being deinitialized")
108 | }
109 | }
110 |
111 | class Apartment2 {
112 | let number: Int
113 | weak var tenant: Person2?
114 |
115 | init(number: Int) {
116 | self.number = number
117 | }
118 |
119 | deinit {
120 | print("Apartment #\(number) is being deinitialized")
121 | }
122 | }
123 |
124 | var john2: Person2?
125 | var number732: Apartment2?
126 |
127 | john2 = Person2(name: "John Appleseed")
128 | number732 = Apartment2(number: 73)
129 |
130 | john2!.apartment = number732
131 | number732!.tenant = john2
132 |
133 | john2 = nil
134 | number732 = nil
135 |
136 | //=======================================================================
137 | // Unowned References
138 | //=======================================================================
139 |
140 | print("\n==== Unowned References ====")
141 |
142 | class Customer {
143 | let name: String
144 | var card: CreditCard?
145 |
146 | init(name: String) {
147 | self.name = name
148 | }
149 |
150 | deinit {
151 | print("\(name) is being deinitialized")
152 | }
153 | }
154 |
155 | class CreditCard {
156 | let number: UInt64
157 | unowned let customer: Customer
158 |
159 | init(number: UInt64, customer: Customer) {
160 | self.number = number
161 | self.customer = customer
162 | }
163 |
164 | deinit {
165 | print("Card #\(number) is being deinitialized")
166 | }
167 | }
168 |
169 | var jerry: Customer? = Customer(name: "Jerry Steele")
170 | jerry!.card = CreditCard(number: 1234_5678_9012_3456, customer: jerry!)
171 |
172 | jerry = nil
173 |
174 | //=======================================================================
175 | // Unowned References and Implicitly Unwrapped Optional Properties
176 | //=======================================================================
177 |
178 | print("\n==== Unowned References and Implicitly Unwrapped Optional Properties ====")
179 |
180 | class Country {
181 | let name: String
182 | var capitalCity: City!
183 |
184 | init(name: String, capitalName: String) {
185 | self.name = name
186 | self.capitalCity = City(name: capitalName, country: self)
187 | }
188 |
189 | deinit {
190 | print("\(name) is being deinitialized")
191 | }
192 | }
193 |
194 | class City {
195 | let name: String
196 | unowned let country: Country
197 |
198 | init(name: String, country: Country) {
199 | self.name = name
200 | self.country = country
201 | }
202 |
203 | deinit {
204 | print("\(name) is being deinitialized")
205 | }
206 | }
207 |
208 | var country: Country? = Country(name: "Canada", capitalName: "Ottawa")
209 | print("Country: \"\(country!.name)\" with Capital City: \"\(country!.capitalCity.name)\"")
210 | country = nil
211 |
212 | //=======================================================================
213 | // Strong Reference Cycles for Closures
214 | //=======================================================================
215 |
216 | print("\n==== Strong Reference Cycles for Closures ====")
217 |
218 | class HTMLElement {
219 | let name: String
220 | let text: String?
221 |
222 | lazy var asHTML: () -> String = {
223 | if let text = self.text {
224 | return "<\(self.name)>\(text)\(self.name)>"
225 | } else {
226 | return "<\(self.name) />"
227 | }
228 | }
229 |
230 | init(name: String, text: String? = nil) {
231 | self.name = name
232 | self.text = text
233 | }
234 |
235 | deinit {
236 | print("\(name) is being deinitialized")
237 | }
238 | }
239 |
240 | var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
241 | let htmlClosure = paragraph!.asHTML
242 | print(htmlClosure())
243 |
244 | paragraph = nil
245 | print("paragraph is not deinitialized b/c the closure is holding onto paragraph")
246 |
247 | //=======================================================================
248 | // Resolving Strong Reference Cycles for Closures
249 | //=======================================================================
250 |
251 | print("\n==== Resolving Strong Reference Cycles for Closures ====")
252 |
253 | class HTMLElement2 {
254 | let name: String
255 | let text: String?
256 |
257 | lazy var asHTML: () -> String = {
258 | [unowned self] in
259 | if let text = self.text {
260 | return "<\(self.name)>\(text)\(self.name)>"
261 | } else {
262 | return "<\(self.name) />"
263 | }
264 | }
265 |
266 | init(name: String, text: String?) {
267 | self.name = name
268 | self.text = text
269 | }
270 |
271 | deinit {
272 | print("\(name) is being deinitialized")
273 | }
274 | }
275 |
276 | var paragraph2: HTMLElement2? = HTMLElement2(name: "p", text: "hello, world")
277 | let htmlClosure2 = paragraph2!.asHTML
278 | print(htmlClosure2())
279 | paragraph2 = nil
280 |
--------------------------------------------------------------------------------
/17 - Optional Chaining.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/17 - Optional Chaining.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/17 - Optional Chaining.playground/section-1.swift:
--------------------------------------------------------------------------------
1 |
2 | //====================================================================
3 | // Optional Chaining as an Alternative to Forced Unwrapping
4 | //====================================================================
5 |
6 | // Optional chaining
7 | class Actor {
8 | var property: Property?
9 | }
10 |
11 | class Property {
12 | var numberOfHomes = 1
13 | }
14 |
15 | let jerry = Actor()
16 | //let homeCount = property!.numberOfHomes // runtime error
17 |
18 | if let numberOfHomes = jerry.property?.numberOfHomes {
19 | print("John's property has \(numberOfHomes) home(s).")
20 | } else {
21 | print("Unable to retrieve the number of homes.")
22 | }
23 |
24 | // Add a property to jerry and requery
25 | jerry.property = Property()
26 | if let numberOfHomes = jerry.property?.numberOfHomes {
27 | print("John's property has \(numberOfHomes) home(s).")
28 | } else {
29 | print("Unable to retrieve the number of homes.")
30 | }
31 |
32 | //====================================================================
33 | // Defining Model Classes for Optional Chaining
34 | //====================================================================
35 |
36 | class Person {
37 | var residence: Residence?
38 | }
39 |
40 | class Residence {
41 | var address: Address?
42 | var rooms = [Room]()
43 | var numberOfRooms: Int { return rooms.count }
44 |
45 | subscript(i: Int) -> Room {
46 | get {
47 | return rooms[i]
48 | }
49 | set {
50 | rooms[i] = newValue
51 | }
52 | }
53 |
54 | func printNumberOfRooms() {
55 | print("The number of rooms is \(numberOfRooms)")
56 | }
57 | }
58 |
59 | class Room {
60 | let name: String
61 |
62 | init(name: String) {
63 | self.name = name
64 | }
65 | }
66 |
67 | class Address {
68 | var buildingName: String?
69 | var buildingNumber: String?
70 | var street: String?
71 |
72 | func buildingIdentifier() -> String? {
73 | if buildingName != nil {
74 | return buildingName
75 | } else if buildingNumber != nil {
76 | return buildingNumber
77 | } else {
78 | return nil
79 | }
80 | }
81 | }
82 |
83 | //====================================================================
84 | // Accessing Properties Through Optional Chaining
85 | //====================================================================
86 |
87 | let john = Person()
88 |
89 | if let roomCount = john.residence?.numberOfRooms {
90 | print("John's residence has \(roomCount) room(s)")
91 | } else {
92 | print("Unable to retrieve the number of rooms.")
93 | }
94 |
95 | let someAddress = Address()
96 | someAddress.buildingNumber = "29"
97 | someAddress.street = "Acacia Road"
98 | john.residence?.address = someAddress // fails b/c residence is nil
99 |
100 | //====================================================================
101 | // Calling Methods Through Optional Chaining
102 | //====================================================================
103 |
104 | if john.residence?.printNumberOfRooms() != nil {
105 | print("It was possible to print the number of rooms")
106 | } else {
107 | print("It was NOT possible to print the number of rooms")
108 | }
109 |
110 | if (john.residence?.address = someAddress) != nil {
111 | print("It was possible to set the address.")
112 | } else {
113 | print("It was NOT possible to set the address.")
114 | }
115 |
116 | //====================================================================
117 | // Accessing Subscripts Through Optional Chaining
118 | //====================================================================
119 |
120 | if let firstRoomName = john.residence?[0].name {
121 | print("The first room name is \(firstRoomName)")
122 | } else {
123 | print("Unable to retrieve the first room name.")
124 | }
125 |
126 | john.residence?[0] = Room(name: "Bathroom") // fails b/c residence is nil
127 |
128 | // Actually create a residence
129 | let johnsHouse = Residence()
130 | johnsHouse.rooms.append(Room(name: "Living Room"))
131 | johnsHouse.rooms.append(Room(name: "Kitchen"))
132 | john.residence = johnsHouse
133 |
134 | if let firstRoomName = john.residence?[0].name {
135 | print("The first room name is \(firstRoomName)")
136 | } else {
137 | print("Unable to retrieve the first room name.")
138 | }
139 |
140 | // Accessing subscripts of optional type
141 | var testScores = ["Dave": [86, 82, 84], "Tim": [79, 94, 81]]
142 | testScores["Dave"]?[0] = 91
143 | testScores["Tim"]?[0] += 1
144 | testScores["Brian"]?[0] = 72
145 |
146 | var davesScores = testScores["Dave"]
147 | davesScores?[1] = 62
148 | testScores["Dave"] = davesScores
149 |
150 | print(testScores)
151 |
152 | //====================================================================
153 | // Link Multiple Levels of Chaining
154 | //====================================================================
155 |
156 | if let johnsStreet = john.residence?.address?.street {
157 | print("John's street name is \(johnsStreet)")
158 | } else {
159 | print("Unable to retrieve the address.")
160 | }
161 |
162 | let johnsAddress = Address()
163 | johnsAddress.buildingName = "The Larches"
164 | johnsAddress.street = "Laurel Street"
165 | john.residence!.address = johnsAddress
166 |
167 | if let johnsStreet = john.residence?.address?.street {
168 | print("John's street name is \(johnsStreet)")
169 | } else {
170 | print("Unable to retrieve the address.")
171 | }
172 |
173 | //====================================================================
174 | // Chaining on Methods with Optional Return Values
175 | //====================================================================
176 |
177 | if let buildingIdentifier = john.residence?.address?.buildingIdentifier() {
178 | print("John's building identifier is \(buildingIdentifier)")
179 | }
180 |
181 | if let beginsWithThe = john.residence?.address?.buildingIdentifier()?.hasPrefix("The") {
182 | if beginsWithThe {
183 | print("John's building identifier begins with \"The\".")
184 | } else {
185 | print("John's building identifier does NOT begin with \"The\".")
186 | }
187 | }
188 |
--------------------------------------------------------------------------------
/18 - Type Casting.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/18 - Type Casting.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/18 - Type Casting.playground/section-1.swift:
--------------------------------------------------------------------------------
1 |
2 | //====================================================================
3 | // Defining a Class Hierarchy for Type Casting
4 | //====================================================================
5 |
6 | class MediaItem {
7 | var name: String
8 |
9 | init(name: String) {
10 | self.name = name
11 | }
12 | }
13 |
14 | class Movie: MediaItem {
15 | var director: String
16 |
17 | init(name: String, director: String) {
18 | self.director = director
19 | super.init(name: name)
20 | }
21 | }
22 |
23 | class Song: MediaItem {
24 | var artist: String
25 |
26 | init(name: String, artist: String) {
27 | self.artist = artist
28 | super.init(name: name)
29 | }
30 | }
31 |
32 | // library type is inferred as [MediaItem]
33 | let library = [
34 | Movie(name: "Casablanca", director: "Michael Curtiz"),
35 | Song(name: "Blue Suede Shoes", artist: "Elvis Presley"),
36 | Movie(name: "Citizen Kane", director: "Orsen Wells"),
37 | Song(name: "The One And Only", artist: "Chesney Hawkes"),
38 | Song(name: "Never Gonna Give You Up", artist: "Rick Astley")
39 | ]
40 |
41 | //====================================================================
42 | // Checking Type
43 | //====================================================================
44 |
45 | var movieCount = 0
46 | var songCount = 0
47 |
48 | for item in library {
49 | if item is Movie {
50 | movieCount += 1
51 | } else if item is Song {
52 | songCount += 1
53 | }
54 | }
55 |
56 | print("Media library contains \(movieCount) movies and \(songCount) songs.")
57 |
58 | //====================================================================
59 | // Downcasting
60 | //====================================================================
61 |
62 | print()
63 |
64 | for item in library {
65 | if let movie = item as? Movie {
66 | print("Movie: \(movie.name) - Directed by: \(movie.director)")
67 | } else if let song = item as? Song {
68 | print("Song: \(song.name) - Performed by: \(song.artist)")
69 | }
70 | }
71 |
72 | //====================================================================
73 | // Type Casting for Any and AnyObject
74 | //====================================================================
75 |
76 | print()
77 |
78 | // AnyObject
79 | let someObjects = [
80 | Movie(name: "2001: A Space Odyssey", director: "Stanley Kubrick"),
81 | Movie(name: "Moon", director: "Duncan Jones"),
82 | Movie(name: "Alien", director: "Ridley Scott")
83 | ]
84 |
85 | for object in someObjects {
86 | let movie = object as Movie
87 | print("Movie: \(movie.name) - Directed by: \(movie.director)")
88 | }
89 |
90 | print()
91 |
92 | for movie in someObjects as [Movie] {
93 | print("Movie: \(movie.name) - Directed by: \(movie.director)")
94 | }
95 |
96 | // Any
97 | var things = [Any]()
98 | things.append(0)
99 | things.append(0.0)
100 | things.append(42)
101 | things.append(3.14159)
102 | things.append("hello")
103 | things.append((3.0, 5.0))
104 | things.append(Movie(name: "Ghostbusters", director: "Ivan Reitman"))
105 |
106 | print()
107 |
108 | for thing in things {
109 | switch thing {
110 | case 0 as Int:
111 | print("Zero as an Int")
112 | case 0 as Float:
113 | print("Zero as a Float")
114 | case 0 as Double:
115 | print("Zero as a Double")
116 | case let someInt as Int:
117 | print("An integer value of \(someInt)")
118 | case let someDouble as Double where someDouble > 0:
119 | print("A positive double value of \(someDouble)")
120 | case is Double:
121 | print("A double value that I don't want to print")
122 | case let someString as String:
123 | print("A string value of \(someString)")
124 | case let (x, y) as (Double, Double):
125 | print("An (x, y) point of (\(x), \(y))")
126 | case let movie as Movie:
127 | print("A Movie: \(movie.name) - Directed by: \(movie.director)")
128 | default:
129 | print("Something else entirely")
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/19 - Nested Types.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/19 - Nested Types.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/19 - Nested Types.playground/section-1.swift:
--------------------------------------------------------------------------------
1 |
2 | //===================================
3 | // Nested Types in Action
4 | //===================================
5 |
6 | struct BlackjackCard {
7 |
8 | // Suit Enum
9 | enum Suit: Character {
10 | case Spades = "♠"
11 | case Hearts = "♡"
12 | case Diamonds = "♢"
13 | case Clubs = "♣"
14 | }
15 |
16 | // Rank Enum
17 | enum Rank: Int {
18 | case Two = 2, Three, Four, Five, Six, Seven, Eight, Nine, Ten
19 | case Jack, Queen, King, Ace
20 |
21 | struct Values {
22 | let first: Int, second: Int?
23 | }
24 |
25 | var values: Values {
26 | switch self {
27 | case .Ace:
28 | return Values(first: 1, second: 11)
29 | case .Jack, .Queen, .King:
30 | return Values(first: 10, second: nil)
31 | default:
32 | return Values(first: self.rawValue, second: nil)
33 | }
34 | }
35 | }
36 |
37 | // Instance Properties
38 | let rank: Rank
39 | let suit: Suit
40 | var description: String {
41 | var output = "Suit is \(suit.rawValue), value is \(rank.values.first)"
42 |
43 | if let second = rank.values.second {
44 | output += " or \(second)"
45 | }
46 |
47 | return output
48 | }
49 | }
50 |
51 | let theAceOfSpades = BlackjackCard(rank: .Ace, suit: .Spades)
52 | print("theAceOfSpades: \(theAceOfSpades.description)")
53 |
54 | //===================================
55 | // Referring to Nested Types
56 | //===================================
57 |
58 | let heartsSymbol = BlackjackCard.Suit.Hearts.rawValue
59 |
--------------------------------------------------------------------------------
/20 - Extensions/20 - Extensions.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 4C891B1219B39CB40001EAD9 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C891B1119B39CB40001EAD9 /* main.swift */; };
11 | /* End PBXBuildFile section */
12 |
13 | /* Begin PBXCopyFilesBuildPhase section */
14 | 4C891B0C19B39CB40001EAD9 /* CopyFiles */ = {
15 | isa = PBXCopyFilesBuildPhase;
16 | buildActionMask = 2147483647;
17 | dstPath = /usr/share/man/man1/;
18 | dstSubfolderSpec = 0;
19 | files = (
20 | );
21 | runOnlyForDeploymentPostprocessing = 1;
22 | };
23 | /* End PBXCopyFilesBuildPhase section */
24 |
25 | /* Begin PBXFileReference section */
26 | 4C891B0E19B39CB40001EAD9 /* 20 - Extensions */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "20 - Extensions"; sourceTree = BUILT_PRODUCTS_DIR; };
27 | 4C891B1119B39CB40001EAD9 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; };
28 | /* End PBXFileReference section */
29 |
30 | /* Begin PBXFrameworksBuildPhase section */
31 | 4C891B0B19B39CB40001EAD9 /* Frameworks */ = {
32 | isa = PBXFrameworksBuildPhase;
33 | buildActionMask = 2147483647;
34 | files = (
35 | );
36 | runOnlyForDeploymentPostprocessing = 0;
37 | };
38 | /* End PBXFrameworksBuildPhase section */
39 |
40 | /* Begin PBXGroup section */
41 | 4C891B0519B39CB40001EAD9 = {
42 | isa = PBXGroup;
43 | children = (
44 | 4C891B1019B39CB40001EAD9 /* 20 - Extensions */,
45 | 4C891B0F19B39CB40001EAD9 /* Products */,
46 | );
47 | sourceTree = "";
48 | };
49 | 4C891B0F19B39CB40001EAD9 /* Products */ = {
50 | isa = PBXGroup;
51 | children = (
52 | 4C891B0E19B39CB40001EAD9 /* 20 - Extensions */,
53 | );
54 | name = Products;
55 | sourceTree = "";
56 | };
57 | 4C891B1019B39CB40001EAD9 /* 20 - Extensions */ = {
58 | isa = PBXGroup;
59 | children = (
60 | 4C891B1119B39CB40001EAD9 /* main.swift */,
61 | );
62 | path = "20 - Extensions";
63 | sourceTree = "";
64 | };
65 | /* End PBXGroup section */
66 |
67 | /* Begin PBXNativeTarget section */
68 | 4C891B0D19B39CB40001EAD9 /* 20 - Extensions */ = {
69 | isa = PBXNativeTarget;
70 | buildConfigurationList = 4C891B1519B39CB40001EAD9 /* Build configuration list for PBXNativeTarget "20 - Extensions" */;
71 | buildPhases = (
72 | 4C891B0A19B39CB40001EAD9 /* Sources */,
73 | 4C891B0B19B39CB40001EAD9 /* Frameworks */,
74 | 4C891B0C19B39CB40001EAD9 /* CopyFiles */,
75 | );
76 | buildRules = (
77 | );
78 | dependencies = (
79 | );
80 | name = "20 - Extensions";
81 | productName = "20 - Extensions";
82 | productReference = 4C891B0E19B39CB40001EAD9 /* 20 - Extensions */;
83 | productType = "com.apple.product-type.tool";
84 | };
85 | /* End PBXNativeTarget section */
86 |
87 | /* Begin PBXProject section */
88 | 4C891B0619B39CB40001EAD9 /* Project object */ = {
89 | isa = PBXProject;
90 | attributes = {
91 | LastSwiftUpdateCheck = 0730;
92 | LastUpgradeCheck = 0730;
93 | ORGANIZATIONNAME = Noondev;
94 | TargetAttributes = {
95 | 4C891B0D19B39CB40001EAD9 = {
96 | CreatedOnToolsVersion = 6.0;
97 | };
98 | };
99 | };
100 | buildConfigurationList = 4C891B0919B39CB40001EAD9 /* Build configuration list for PBXProject "20 - Extensions" */;
101 | compatibilityVersion = "Xcode 3.2";
102 | developmentRegion = English;
103 | hasScannedForEncodings = 0;
104 | knownRegions = (
105 | en,
106 | );
107 | mainGroup = 4C891B0519B39CB40001EAD9;
108 | productRefGroup = 4C891B0F19B39CB40001EAD9 /* Products */;
109 | projectDirPath = "";
110 | projectRoot = "";
111 | targets = (
112 | 4C891B0D19B39CB40001EAD9 /* 20 - Extensions */,
113 | );
114 | };
115 | /* End PBXProject section */
116 |
117 | /* Begin PBXSourcesBuildPhase section */
118 | 4C891B0A19B39CB40001EAD9 /* Sources */ = {
119 | isa = PBXSourcesBuildPhase;
120 | buildActionMask = 2147483647;
121 | files = (
122 | 4C891B1219B39CB40001EAD9 /* main.swift in Sources */,
123 | );
124 | runOnlyForDeploymentPostprocessing = 0;
125 | };
126 | /* End PBXSourcesBuildPhase section */
127 |
128 | /* Begin XCBuildConfiguration section */
129 | 4C891B1319B39CB40001EAD9 /* Debug */ = {
130 | isa = XCBuildConfiguration;
131 | buildSettings = {
132 | ALWAYS_SEARCH_USER_PATHS = NO;
133 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
134 | CLANG_CXX_LIBRARY = "libc++";
135 | CLANG_ENABLE_MODULES = YES;
136 | CLANG_ENABLE_OBJC_ARC = YES;
137 | CLANG_WARN_BOOL_CONVERSION = YES;
138 | CLANG_WARN_CONSTANT_CONVERSION = YES;
139 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
140 | CLANG_WARN_EMPTY_BODY = YES;
141 | CLANG_WARN_ENUM_CONVERSION = YES;
142 | CLANG_WARN_INT_CONVERSION = YES;
143 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
144 | CLANG_WARN_UNREACHABLE_CODE = YES;
145 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
146 | COPY_PHASE_STRIP = NO;
147 | ENABLE_STRICT_OBJC_MSGSEND = YES;
148 | ENABLE_TESTABILITY = YES;
149 | GCC_C_LANGUAGE_STANDARD = gnu99;
150 | GCC_DYNAMIC_NO_PIC = NO;
151 | GCC_OPTIMIZATION_LEVEL = 0;
152 | GCC_PREPROCESSOR_DEFINITIONS = (
153 | "DEBUG=1",
154 | "$(inherited)",
155 | );
156 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
157 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
158 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
159 | GCC_WARN_UNDECLARED_SELECTOR = YES;
160 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
161 | GCC_WARN_UNUSED_FUNCTION = YES;
162 | GCC_WARN_UNUSED_VARIABLE = YES;
163 | MACOSX_DEPLOYMENT_TARGET = 10.9;
164 | MTL_ENABLE_DEBUG_INFO = YES;
165 | ONLY_ACTIVE_ARCH = YES;
166 | SDKROOT = macosx;
167 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
168 | };
169 | name = Debug;
170 | };
171 | 4C891B1419B39CB40001EAD9 /* Release */ = {
172 | isa = XCBuildConfiguration;
173 | buildSettings = {
174 | ALWAYS_SEARCH_USER_PATHS = NO;
175 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
176 | CLANG_CXX_LIBRARY = "libc++";
177 | CLANG_ENABLE_MODULES = YES;
178 | CLANG_ENABLE_OBJC_ARC = YES;
179 | CLANG_WARN_BOOL_CONVERSION = YES;
180 | CLANG_WARN_CONSTANT_CONVERSION = YES;
181 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
182 | CLANG_WARN_EMPTY_BODY = YES;
183 | CLANG_WARN_ENUM_CONVERSION = YES;
184 | CLANG_WARN_INT_CONVERSION = YES;
185 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
186 | CLANG_WARN_UNREACHABLE_CODE = YES;
187 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
188 | COPY_PHASE_STRIP = YES;
189 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
190 | ENABLE_NS_ASSERTIONS = NO;
191 | ENABLE_STRICT_OBJC_MSGSEND = YES;
192 | GCC_C_LANGUAGE_STANDARD = gnu99;
193 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
194 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
195 | GCC_WARN_UNDECLARED_SELECTOR = YES;
196 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
197 | GCC_WARN_UNUSED_FUNCTION = YES;
198 | GCC_WARN_UNUSED_VARIABLE = YES;
199 | MACOSX_DEPLOYMENT_TARGET = 10.9;
200 | MTL_ENABLE_DEBUG_INFO = NO;
201 | SDKROOT = macosx;
202 | };
203 | name = Release;
204 | };
205 | 4C891B1619B39CB40001EAD9 /* Debug */ = {
206 | isa = XCBuildConfiguration;
207 | buildSettings = {
208 | PRODUCT_NAME = "$(TARGET_NAME)";
209 | SDKROOT = macosx;
210 | };
211 | name = Debug;
212 | };
213 | 4C891B1719B39CB40001EAD9 /* Release */ = {
214 | isa = XCBuildConfiguration;
215 | buildSettings = {
216 | PRODUCT_NAME = "$(TARGET_NAME)";
217 | SDKROOT = macosx;
218 | };
219 | name = Release;
220 | };
221 | /* End XCBuildConfiguration section */
222 |
223 | /* Begin XCConfigurationList section */
224 | 4C891B0919B39CB40001EAD9 /* Build configuration list for PBXProject "20 - Extensions" */ = {
225 | isa = XCConfigurationList;
226 | buildConfigurations = (
227 | 4C891B1319B39CB40001EAD9 /* Debug */,
228 | 4C891B1419B39CB40001EAD9 /* Release */,
229 | );
230 | defaultConfigurationIsVisible = 0;
231 | defaultConfigurationName = Release;
232 | };
233 | 4C891B1519B39CB40001EAD9 /* Build configuration list for PBXNativeTarget "20 - Extensions" */ = {
234 | isa = XCConfigurationList;
235 | buildConfigurations = (
236 | 4C891B1619B39CB40001EAD9 /* Debug */,
237 | 4C891B1719B39CB40001EAD9 /* Release */,
238 | );
239 | defaultConfigurationIsVisible = 0;
240 | defaultConfigurationName = Release;
241 | };
242 | /* End XCConfigurationList section */
243 | };
244 | rootObject = 4C891B0619B39CB40001EAD9 /* Project object */;
245 | }
246 |
--------------------------------------------------------------------------------
/20 - Extensions/20 - Extensions.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/20 - Extensions/20 - Extensions/main.swift:
--------------------------------------------------------------------------------
1 | //
2 | // main.swift
3 | // 20 - Extensions
4 | //
5 | // Created by Christian Noon on 8/31/14.
6 | // Copyright (c) 2014 Noondev. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | //===================================
12 | // Computed Properties
13 | //===================================
14 |
15 | print("==== Computed Properties ====")
16 |
17 | extension Double {
18 | var km: Double { return self * 1_000.0 }
19 | var m: Double { return self }
20 | var cm: Double { return self / 100.0 }
21 | var mm: Double { return self / 1_000.0 }
22 | var ft: Double { return self / 3.28084 }
23 | }
24 |
25 | let oneInch = 25.4.mm
26 | print("One inch is \(oneInch) meters")
27 |
28 | let threeFeet = 3.ft
29 | print("Three feet is \(threeFeet) meters")
30 |
31 | let aMarathon = 42.km + 195.m
32 | print("A marathon is \(aMarathon) meters long")
33 |
34 | //===================================
35 | // Initializers
36 | //===================================
37 |
38 | print("\n==== Initializers ====")
39 |
40 | struct Point {
41 | var x = 0.0
42 | var y = 0.0
43 | }
44 |
45 | struct Size {
46 | var width = 0.0
47 | var height = 0.0
48 | }
49 |
50 | struct Rect {
51 | var origin = Point()
52 | var size = Size()
53 |
54 | var description: String {
55 | return "((\(origin.x), \(origin.y)), (\(size.width), \(size.height)))"
56 | }
57 | }
58 |
59 | let defaultRect = Rect()
60 | print("defaultRect: \(defaultRect.description)")
61 | let memberwiseRect = Rect(origin: Point(x: 2.0, y: 2.0), size: Size(width: 5.0, height: 5.0))
62 | print("memberwiseRect: \(memberwiseRect.description)")
63 |
64 | extension Rect {
65 | init(center: Point, size: Size) {
66 | let originX = center.x - (size.width / 2.0)
67 | let originY = center.y - (size.height / 2.0)
68 | self.init(origin: Point(x: originX, y: originY), size: size)
69 | }
70 | }
71 |
72 | let centerRect = Rect(center: Point(x: 4.0, y: 4.0), size: Size(width: 3.0, height: 3.0))
73 | print("centerRect: \(centerRect.description)")
74 |
75 | //===================================
76 | // Methods
77 | //===================================
78 |
79 | print("\n==== Methods ====")
80 |
81 | extension Int {
82 | func repititions(task: () -> ()) {
83 | for _ in 1...self { task() }
84 | }
85 | }
86 |
87 | 3.repititions({
88 | print("Hello!")
89 | })
90 |
91 | 3.repititions {
92 | print("Goodbye!")
93 | }
94 |
95 | // Mutating instance methods
96 | extension Int {
97 | mutating func square() {
98 | self = self * self
99 | }
100 | }
101 |
102 | var someInt = 3
103 | someInt.square()
104 | print("someInt squared: \(someInt)")
105 |
106 | //===================================
107 | // Subscripts
108 | //===================================
109 |
110 | print("\n==== Subscripts ====")
111 |
112 | extension Int {
113 | subscript(digitIndex: Int) -> Int {
114 | var digitIndex = digitIndex
115 | var decimalBase = 1
116 |
117 | while digitIndex > 0 {
118 | decimalBase *= 10
119 | digitIndex -= 1
120 | }
121 |
122 | return (self / decimalBase) % 10
123 | }
124 | }
125 |
126 | print("746381295[0]: \(746381295[0])")
127 | print("746381295[1]: \(746381295[1])")
128 | print("746381295[2]: \(746381295[2])")
129 | print("746381295[8]: \(746381295[8])")
130 | print("746381295[9]: \(746381295[9])") // returns 0 as if it were padded
131 |
132 | //===================================
133 | // Nested Types
134 | //===================================
135 |
136 | print("\n==== Nested Types ====")
137 |
138 | extension Int {
139 | enum Kind {
140 | case Negative
141 | case Zero
142 | case Positive
143 | }
144 |
145 | var kind: Kind {
146 | switch self {
147 | case 0:
148 | return .Zero
149 | case let x where x > 0:
150 | return .Positive
151 | default:
152 | return .Negative
153 | }
154 | }
155 | }
156 |
157 | func printIntegerKinds(numbers: [Int]) {
158 | for number in numbers {
159 | switch number.kind {
160 | case .Negative:
161 | print("- ")
162 | case .Zero:
163 | print("0 ")
164 | case .Positive:
165 | print("+ ")
166 | }
167 | }
168 |
169 | print()
170 | }
171 |
172 | printIntegerKinds([3, 19, -27, 0, -6, 0, 7])
173 |
--------------------------------------------------------------------------------
/21 - Protocols.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/21 - Protocols.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/21 - Protocols.playground/section-1.swift:
--------------------------------------------------------------------------------
1 |
2 | import Foundation
3 |
4 | //======================================================
5 | // Protocol Syntax
6 | //======================================================
7 |
8 | protocol FirstProtocol {}
9 | protocol SecondProtocol {}
10 |
11 | struct SomeStructure: FirstProtocol, SecondProtocol {}
12 |
13 | class SomeSuperclass {}
14 | class SomeClass: SomeSuperclass, FirstProtocol, SecondProtocol {}
15 |
16 | //======================================================
17 | // Protocol Requirements
18 | //======================================================
19 |
20 | // Instance property protocol
21 | protocol SomeProtocol {
22 | var mustBeSettable: Int { get set }
23 | var doesNotNeedToBeSettable: Int { get }
24 | }
25 |
26 | // Type property protocol
27 | protocol AnotherProtocol {
28 | static var sometTypeProperty: Int { get set }
29 | }
30 |
31 | // Instance property protocol
32 | protocol FullyNamed {
33 | var fullName: String { get }
34 | }
35 |
36 | struct Person: FullyNamed {
37 | var fullName: String
38 | }
39 |
40 | let john = Person(fullName: "John Appleseed")
41 |
42 | class Starship: FullyNamed {
43 | var name: String
44 | var prefix: String?
45 |
46 | var fullName: String {
47 | return (prefix != nil ? prefix! + " " : "") + name
48 | }
49 |
50 | init(name: String, prefix: String?) {
51 | self.name = name
52 | self.prefix = prefix
53 | }
54 | }
55 |
56 | var ncc1701 = Starship(name: "Enterprise", prefix: "USS")
57 | ncc1701.fullName
58 |
59 | //======================================================
60 | // Method Requirements
61 | //======================================================
62 |
63 | protocol SomeTypeProtocol {
64 | static func someTypeMethod()
65 | }
66 |
67 | protocol RandomNumberGenerator {
68 | func random() -> Double
69 | }
70 |
71 | class LinearConguentialGenerator: RandomNumberGenerator {
72 | var lastRandom = 42.0
73 | let m = 139968.0
74 | let a = 3877.0
75 | let c = 29573.0
76 |
77 | func random() -> Double {
78 | lastRandom = ((lastRandom * a + c) % m)
79 | return lastRandom / m
80 | }
81 | }
82 |
83 | let generator = LinearConguentialGenerator()
84 | print("Here's a random number: \(generator.random())")
85 | print("And another one: \(generator.random())")
86 |
87 | //======================================================
88 | // Mutating Method Requirements
89 | //======================================================
90 |
91 | protocol Togglable {
92 | mutating func toggle()
93 | }
94 |
95 | enum OnOffSwitch: Togglable {
96 | case Off, On
97 |
98 | mutating func toggle() {
99 | switch self {
100 | case .Off:
101 | self = .On
102 | case .On:
103 | self = .Off
104 | }
105 | }
106 | }
107 |
108 | var lightSwitch = OnOffSwitch.Off
109 | lightSwitch == .Off
110 | lightSwitch.toggle()
111 | lightSwitch == .On
112 |
113 | //======================================================
114 | // Initializer Requirements
115 | //======================================================
116 |
117 | protocol SomeInitProtocol {
118 | init(someParameter: Int)
119 | }
120 |
121 | class SomeInitClass: SomeInitProtocol {
122 | required init(someParameter: Int) {}
123 | }
124 |
125 | protocol SomeEmptyProtocol {
126 | init()
127 | }
128 |
129 | class SomeEmptySuperClass {
130 | init() {}
131 | }
132 |
133 | class SomeEmptySubClass: SomeEmptySuperClass, SomeEmptyProtocol {
134 | required override init() {}
135 | }
136 |
137 | //======================================================
138 | // Protocols as Types
139 | //======================================================
140 |
141 | class Dice {
142 | let sides: Int
143 | let generator: RandomNumberGenerator
144 |
145 | init(sides: Int, generator: RandomNumberGenerator) {
146 | self.sides = sides
147 | self.generator = generator
148 | }
149 |
150 | func roll() -> Int {
151 | return Int(generator.random() * Double(sides)) + 1
152 | }
153 | }
154 |
155 | var d6 = Dice(sides: 6, generator: LinearConguentialGenerator())
156 |
157 | for _ in 1...6 {
158 | print("Random dice roll is \(d6.roll())")
159 | }
160 |
161 | //======================================================
162 | // Delegation
163 | //======================================================
164 |
165 | print()
166 |
167 | protocol DiceGame {
168 | var dice: Dice { get }
169 | func play()
170 | }
171 |
172 | protocol DiceGameDelegate {
173 | func gameDidStart(game: DiceGame)
174 | func game(game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int)
175 | func gameDidEnd(game: DiceGame)
176 | }
177 |
178 | class SnakesAndLadders: DiceGame {
179 | let finalSquare = 25
180 | let dice = Dice(sides: 6, generator: LinearConguentialGenerator())
181 | var square = 0
182 | var board: [Int]
183 | var delegate: DiceGameDelegate?
184 |
185 | init() {
186 | board = [Int](count: finalSquare + 1, repeatedValue: 0)
187 | board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
188 | board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
189 | }
190 |
191 | func play() {
192 | square = 0
193 | delegate?.gameDidStart(self)
194 |
195 | gameloop: while square != finalSquare {
196 | let diceRoll = dice.roll()
197 | delegate?.game(self, didStartNewTurnWithDiceRoll: diceRoll)
198 |
199 | switch square + diceRoll {
200 | case finalSquare:
201 | break gameloop
202 | case let newSquare where newSquare > finalSquare:
203 | continue gameloop
204 | default:
205 | square += diceRoll
206 | square += board[square]
207 | }
208 | }
209 |
210 | delegate?.gameDidEnd(self)
211 | }
212 | }
213 |
214 | class DiceGameTracker: DiceGameDelegate {
215 | var numberOfTurns = 0
216 |
217 | func gameDidStart(game: DiceGame) {
218 | numberOfTurns = 0
219 | if game is SnakesAndLadders {
220 | print("Started a new game of Snakes and Ladders")
221 | }
222 | print("The game is using a \(game.dice.sides) sided dice.")
223 | }
224 |
225 | func game(game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int) {
226 | numberOfTurns += 1
227 | print("Rolled a \(diceRoll)")
228 | }
229 |
230 | func gameDidEnd(game: DiceGame) {
231 | print("The game lasted for \(numberOfTurns) turn(s)")
232 | }
233 | }
234 |
235 | let tracker = DiceGameTracker()
236 | let game = SnakesAndLadders()
237 | game.delegate = tracker
238 | game.play()
239 |
240 | //======================================================
241 | // Adding Protocol Conformance with an Extension
242 | //======================================================
243 |
244 | print()
245 |
246 | protocol TextRepresentable {
247 | func asText() -> String
248 | }
249 |
250 | extension Dice: TextRepresentable {
251 | func asText() -> String {
252 | return "A \(sides)-sided dice"
253 | }
254 | }
255 |
256 | let d12 = Dice(sides: 12, generator: LinearConguentialGenerator())
257 | print(d12.asText())
258 |
259 | extension SnakesAndLadders: TextRepresentable {
260 | func asText() -> String {
261 | return "A game of Snakes and Ladders with \(finalSquare) squares"
262 | }
263 | }
264 |
265 | print(game.asText())
266 |
267 | // Declaring Protocol Adoption with an Extension
268 | struct Hamster {
269 | var name: String
270 |
271 | func asText() -> String {
272 | return "A hamster named \(name)"
273 | }
274 | }
275 | extension Hamster: TextRepresentable {}
276 |
277 | let simonTheHamster = Hamster(name: "Simon")
278 | let somethingTextRepresentable: TextRepresentable = simonTheHamster
279 | print(simonTheHamster.asText())
280 |
281 | //======================================================
282 | // Collections of Protocol Types
283 | //======================================================
284 |
285 | print()
286 |
287 | let things: [TextRepresentable] = [game, d12, simonTheHamster]
288 |
289 | for thing in things {
290 | print(thing.asText())
291 | }
292 |
293 | //======================================================
294 | // Protocol Inheritance
295 | //======================================================
296 |
297 | print()
298 |
299 | protocol PrettyTextRepresentable: TextRepresentable {
300 | func asPrettyText() -> String
301 | }
302 |
303 | extension SnakesAndLadders: PrettyTextRepresentable {
304 | func asPrettyText() -> String {
305 | var output = asText() + ":\n"
306 |
307 | for index in 1...finalSquare {
308 | switch board[index] {
309 | case let ladder where ladder > 0:
310 | output += "▲ "
311 | case let snake where snake < 0:
312 | output += "▼ "
313 | default:
314 | output += "○ "
315 | }
316 | }
317 |
318 | return output
319 | }
320 | }
321 |
322 | print(game.asPrettyText())
323 |
324 | //======================================================
325 | // Class-Only Protocols
326 | //======================================================
327 |
328 | print()
329 |
330 | protocol SomeInheritedProtocol {}
331 | protocol SomeClassOnlyProtocol: class, SomeInheritedProtocol {
332 | // class-only protocol definition goes here...
333 | }
334 |
335 | //======================================================
336 | // Protocol Composition
337 | //======================================================
338 |
339 | print()
340 |
341 | protocol Named {
342 | var name: String { get }
343 | }
344 |
345 | protocol Aged {
346 | var age: Int { get }
347 | }
348 |
349 | struct Human: Named, Aged {
350 | var name: String
351 | var age: Int
352 | }
353 |
354 | func wishHappyBirthday(celebrator: protocol) {
355 | print("Happy Birthday \(celebrator.name) - youre \(celebrator.age)")
356 | }
357 |
358 | let birthdayHuman = Human(name: "Malcom", age: 23)
359 | wishHappyBirthday(birthdayHuman)
360 |
361 | //======================================================
362 | // Checking for Protocol Conformance
363 | //======================================================
364 |
365 | print()
366 |
367 | @objc protocol HasArea {
368 | var area: Double { get }
369 | }
370 |
371 | class Circle: HasArea {
372 | let pi = 3.14159
373 | var radius: Double
374 | @objc var area: Double { return pi * radius * radius }
375 |
376 | init(radius: Double) { self.radius = radius }
377 | }
378 |
379 | class Country: HasArea {
380 | @objc var area: Double
381 |
382 | init(area: Double) { self.area = area }
383 | }
384 |
385 | class Animal {
386 | var legs: Int
387 |
388 | init(legs: Int) { self.legs = legs }
389 | }
390 |
391 | let objects: [AnyObject] = [
392 | Circle(radius: 2.0),
393 | Country(area: 243_610),
394 | Animal(legs: 4)
395 | ]
396 |
397 | for object in objects {
398 | if let objectWithArea = object as? HasArea {
399 | print("Area is \(objectWithArea.area)")
400 | } else {
401 | print("Something that doesn't have an area")
402 | }
403 | }
404 |
405 | //======================================================
406 | // Optional Protocol Requirements
407 | //======================================================
408 |
409 | print()
410 |
411 | @objc protocol CounterDataSource {
412 | optional func incrementForCount(count: Int) -> Int
413 | optional var fixedIncrement: Int { get }
414 | }
415 |
416 | class Counter {
417 | var count = 0
418 | var dataSource: CounterDataSource?
419 |
420 | func increment() {
421 | if let amount = dataSource?.incrementForCount?(count) {
422 | count += amount
423 | } else if let amount = dataSource?.fixedIncrement {
424 | count += amount
425 | }
426 | }
427 | }
428 |
429 | class ThreeSource: CounterDataSource {
430 | @objc let fixedIncrement = 3
431 | }
432 |
433 | var counter = Counter()
434 | counter.dataSource = ThreeSource()
435 |
436 | for _ in 1...4 {
437 | counter.increment()
438 | print(counter.count)
439 | }
440 |
441 | print()
442 |
443 | class TowardsZeroSource: CounterDataSource {
444 | @objc func incrementForCount(count: Int) -> Int {
445 | if count == 0 {
446 | return 0
447 | } else if count < 0 {
448 | return 1
449 | } else {
450 | return -1
451 | }
452 | }
453 | }
454 |
455 | counter.count = -4
456 | counter.dataSource = TowardsZeroSource()
457 |
458 | for _ in 1...5 {
459 | counter.increment()
460 | print(counter.count)
461 | }
462 |
--------------------------------------------------------------------------------
/22 - Generics.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/22 - Generics.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/22 - Generics.playground/section-1.swift:
--------------------------------------------------------------------------------
1 |
2 | //=======================================
3 | // The Problem That Generics Solve
4 | //=======================================
5 |
6 | func swapTwoInts(inout a: Int, inout b: Int) {
7 | let temporaryA = a
8 | a = b
9 | b = temporaryA
10 | }
11 |
12 | func swapTwoStrings(inout a: String, inout b: String) {
13 | let temporaryA = a
14 | a = b
15 | b = temporaryA
16 | }
17 |
18 | func swapTwoDoubles(inout a: Double, inout b: Double) {
19 | let temporaryA = a
20 | a = b
21 | b = temporaryA
22 | }
23 |
24 | var someInt = 3
25 | var anotherInt = 107
26 | swapTwoInts(&someInt, b: &anotherInt)
27 | print("someInt: \(someInt) anotherInt: \(anotherInt)")
28 |
29 | //=======================================
30 | // Generic Functions
31 | //=======================================
32 |
33 | print()
34 |
35 | func swapTwoValues(inout a: T, inout b: T) {
36 | let temporaryA = a
37 | a = b
38 | b = temporaryA
39 | }
40 |
41 | someInt = 3
42 | anotherInt = 107
43 | swapTwoValues(&someInt, b: &anotherInt)
44 | print("someInt: \(someInt) anotherInt: \(anotherInt)")
45 |
46 | var someString = "hello"
47 | var anotherString = "world"
48 | swapTwoValues(&someString, b: &anotherString)
49 | print("someString: \(someString) anotherString: \(anotherString)")
50 |
51 | //=======================================
52 | // Naming Type Parameters
53 | //=======================================
54 |
55 | // Always give type parameters UpperCamelCase names (such as T and KeyType)
56 | // to indicate that they are a placeholder for a type, not a value.
57 |
58 | //=======================================
59 | // Generic Types
60 | //=======================================
61 |
62 | print()
63 |
64 | struct IntStack {
65 | var items = [Int]()
66 |
67 | mutating func push(item: Int) {
68 | items.append(item)
69 | }
70 |
71 | mutating func pop() -> Int {
72 | return items.removeLast()
73 | }
74 | }
75 |
76 | struct Stack {
77 | var items = [T]()
78 | var isEmpty: Bool { return items.isEmpty }
79 |
80 | mutating func push(item: T) {
81 | items.append(item)
82 | }
83 |
84 | mutating func pop() -> T {
85 | return items.removeLast()
86 | }
87 | }
88 |
89 | var stackOfStrings = Stack()
90 |
91 | stackOfStrings.push("uno")
92 | stackOfStrings.push("dos")
93 | stackOfStrings.push("tres")
94 | stackOfStrings.push("cuatro")
95 |
96 | while !stackOfStrings.isEmpty {
97 | let fromTheTop = stackOfStrings.pop()
98 | print(fromTheTop)
99 | }
100 |
101 | //=======================================
102 | // Extending a Generic Type
103 | //=======================================
104 |
105 | print()
106 |
107 | extension Stack {
108 | var topItem: T? {
109 | return items.last
110 | }
111 | }
112 |
113 | stackOfStrings.push("uno")
114 | stackOfStrings.push("dos")
115 |
116 | if let topItem = stackOfStrings.topItem {
117 | print("The top item on the stack is \(topItem)")
118 | }
119 |
120 | //=======================================
121 | // Type Constraints
122 | //=======================================
123 |
124 | print()
125 |
126 | // Type constraint syntax
127 | class SomeClass {}
128 | protocol SomeProtocol {}
129 |
130 | // T must inherit from SomeClass, U must conform to SomeProtocol
131 | func someFunction(someT: T, someU: U) {
132 | // function body goes here...
133 | }
134 |
135 | // Type constraints in action
136 | func findStringIndex(array: [String], valueToFind: String) -> Int? {
137 | for (index, value) in array.enumerate() {
138 | if value == valueToFind {
139 | return index
140 | }
141 | }
142 |
143 | return nil
144 | }
145 |
146 | let strings = ["cat", "dog", "llama", "parakeet", "terrapin"]
147 |
148 | if let foundIndex = findStringIndex(strings, valueToFind: "llama") {
149 | print("The index of llama is \(foundIndex)")
150 | }
151 |
152 | func findIndex(array: [T], valueToFind: T) -> Int? {
153 | for (index, value) in array.enumerate() where value == valueToFind {
154 | return index
155 | }
156 |
157 | return nil
158 | }
159 |
160 | if let foundIndex = findIndex(strings, valueToFind: "llama") {
161 | print("The index of llama is \(foundIndex)")
162 | }
163 |
164 | let doubleIndex = findIndex([3.14159, 0.1, 0.25], valueToFind: 9.3)
165 | print(doubleIndex)
166 |
167 | let stringIndex = findIndex(["Mike", "Malcolm", "Andrea"], valueToFind: "Andrea")
168 | print(stringIndex)
169 |
170 | //=======================================
171 | // Associated Types
172 | //=======================================
173 |
174 | print()
175 |
176 | protocol Container {
177 | associatedtype ItemType
178 | mutating func append(item: ItemType)
179 | var count: Int { get }
180 | subscript(i: Int) -> ItemType { get }
181 | }
182 |
183 | struct SuperStack: Container {
184 | var items = [T]()
185 | var isEmpty: Bool { return items.isEmpty }
186 |
187 | mutating func push(item: T) {
188 | items.append(item)
189 | }
190 |
191 | mutating func pop() -> T {
192 | return items.removeLast()
193 | }
194 |
195 | // Container Protocol Conformance
196 | mutating func append(item: T) {
197 | items.append(item)
198 | }
199 |
200 | var count: Int {
201 | return items.count
202 | }
203 |
204 | subscript(i: Int) -> T {
205 | return items[i]
206 | }
207 | }
208 |
209 | var superstack = SuperStack()
210 | superstack.push("Toast")
211 | superstack.push("Ham")
212 | superstack.append("Eggs")
213 | superstack.append("Bacon")
214 | let bacon = superstack.pop()
215 |
216 | print(superstack.count)
217 | print(superstack[1])
218 | print(superstack[2])
219 |
220 | // Extending an existing type to specify an associated type
221 | extension Array: Container {}
222 |
223 | //=======================================
224 | // Where Clauses
225 | //=======================================
226 |
227 | print()
228 |
229 | func allItemsMatch
231 | (someContainer: T1, anotherContainer: T2) -> Bool {
232 | if someContainer.count != anotherContainer.count {
233 | return false
234 | }
235 |
236 | for i in 0..()
246 | stringSuperStack.push("uno")
247 | stringSuperStack.push("dos")
248 | stringSuperStack.push("tres")
249 |
250 | var arrayOfStrings = ["uno", "dos", "tres"]
251 |
252 | if allItemsMatch(stringSuperStack, anotherContainer: arrayOfStrings) {
253 | print("All items match")
254 | } else {
255 | print("Not all items match.")
256 | }
257 |
--------------------------------------------------------------------------------
/23 - Access Control.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/23 - Access Control.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/23 - Access Control.playground/section-1.swift:
--------------------------------------------------------------------------------
1 |
2 | //=======================================================
3 | // Access Control Syntax
4 | //=======================================================
5 |
6 | public class PublicClass {}
7 | internal class InternalClass {}
8 | private class PrivateClass {}
9 |
10 | public var publicVariable = 0
11 | internal let internalConstant = 0
12 | private func privateFunction() {}
13 |
14 | class ImplicitlyInternalClass {} // implicitly internal
15 | var ImplicitlyInternalConstant = 0 // implicitly internal
16 |
17 | //=======================================================
18 | // Custom Types
19 | //=======================================================
20 |
21 | public class SomePublicClass { // explicitly public class
22 | public var somePublicProperty = 0 // explicitly public class member
23 | var someInternalProperty = 0 // implicitly internal class member
24 | private func somePrivateMethod() {} // explicityly private class member
25 | }
26 |
27 | class SomeInternalClass { // implicitly internal class
28 | var someInternalProperty = 0 // implicitly internal class member
29 | private func somePrivateMethod() {} // explicitly private class member
30 | }
31 |
32 | private class SomePrivateClass { // explicitly private class
33 | var somePrivateProperty = 0 // implicityly private class member
34 | func somePrivateMethod() {} // implicityly private class member
35 | }
36 |
37 | //=======================================================
38 | // Tuple Types
39 | //=======================================================
40 |
41 | // Must be defined as private since it's return type contains a private type
42 | private func someFunction() -> (SomeInternalClass, SomePrivateClass) {
43 | return (SomeInternalClass(), SomePrivateClass())
44 | }
45 |
46 | //=======================================================
47 | // Enumeration Types
48 | //=======================================================
49 |
50 | public enum CompassPoint {
51 | case North, South, East, West
52 | }
53 |
54 | // NOTE: the raw and associated values must have the same access level
55 | // as the enum itself
56 |
57 | //=======================================================
58 | // Subclassing
59 | //=======================================================
60 |
61 | public class A {
62 | private func someMethod() {}
63 | }
64 |
65 | internal class B: A {
66 | override internal func someMethod() {
67 | super.someMethod() // only works when A and B defined in same source file
68 | }
69 | }
70 |
71 | //=======================================================
72 | // Constants, Variables, Properties and Subscripts
73 | //=======================================================
74 |
75 | // Getters and Setters
76 | struct TrackedString {
77 | private(set) var numberOfEdits = 0
78 | var value: String = "" {
79 | didSet {
80 | numberOfEdits += 1
81 | }
82 | }
83 | }
84 |
85 | var stringToEdit = TrackedString()
86 | stringToEdit.value = "This string will be tracked."
87 | stringToEdit.value += " This edit will increment numberOfEdits."
88 | stringToEdit.value += " So will this one."
89 | print("The number of edits is \(stringToEdit.numberOfEdits)")
90 |
91 | public struct PublicTrackedString {
92 | public private(set) var numberOfEdits = 0
93 |
94 | var value: String = "" {
95 | didSet {
96 | numberOfEdits += 1
97 | }
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/24 - Advanced Operators.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/24 - Advanced Operators.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/24 - Advanced Operators.playground/section-1.swift:
--------------------------------------------------------------------------------
1 |
2 | //=======================================================
3 | // Bitwise Operators
4 | //=======================================================
5 |
6 | func bitsToString(number: UInt8) -> String {
7 | var number = number
8 | var bitString = ""
9 |
10 | for _ in 0..<8 {
11 | if (number & UInt8(1)) == 1 {
12 | bitString = "1" + bitString
13 | } else {
14 | bitString = "0" + bitString
15 | }
16 |
17 | number = number >> 1
18 | }
19 |
20 | return bitString
21 | }
22 |
23 | // Bitwise NOT Operator - inverts all incoming bits
24 | print("==== Bitwise NOT Operator (~) ====")
25 |
26 | let initialBits: UInt8 = 0b00001111
27 | let invertedBits: UInt8 = ~initialBits
28 |
29 | print("initialBits: \(bitsToString(initialBits))")
30 | print("invertedBits: \(bitsToString(invertedBits))")
31 | print()
32 |
33 | // Bitwise AND Operator - final bit equals 1 if both incoming bits equal 1
34 | print("==== Bitwise AND Operator (&) ====")
35 |
36 | let firstSixBits: UInt8 = 0b11111100
37 | let lastSixBits: UInt8 = 0b00111111
38 | let middleFourBits = firstSixBits & lastSixBits
39 |
40 | print("firstSixBits: \(bitsToString(firstSixBits))")
41 | print("lastSixBits: \(bitsToString(lastSixBits))")
42 | print("middleFourBits: \(bitsToString(middleFourBits))")
43 | print()
44 |
45 | // Bitwise OR Operator - final bit equals 1 if either incoming bit equals 1
46 | print("==== Bitwise OR Operator (|) ====")
47 |
48 | let someBits: UInt8 = 0b10110010
49 | let moreBits: UInt8 = 0b01011110
50 | let combinedBits = someBits | moreBits
51 |
52 | print("someBits: \(bitsToString(someBits))")
53 | print("moreBits: \(bitsToString(moreBits))")
54 | print("combinedBits: \(bitsToString(combinedBits))")
55 | print()
56 |
57 | // Bitwise XOR Operator - final bit equals 1 if incoming bits are different
58 | print("==== Bitwise XOR Operator (^) ====")
59 |
60 | let firstBits: UInt8 = 0b00010100
61 | let otherBits: UInt8 = 0b00000101
62 | let outputBits = firstBits ^ otherBits
63 |
64 | print("firstBits: \(bitsToString(firstBits))")
65 | print("otherBits: \(bitsToString(otherBits))")
66 | print("outputBits: \(bitsToString(outputBits))")
67 | print()
68 |
69 | // Bitwise Left and Right Shift Operators
70 | print("==== Bitwise Left and Right Shift Operators (<< >>) ====")
71 |
72 | let shiftBits: UInt8 = 4 // 00000100
73 | shiftBits << 2 // 00010000
74 | shiftBits << 5 // 10000000
75 | shiftBits << 6 // 00000000
76 | shiftBits >> 2 // 00000001
77 |
78 | let pink: UInt32 = 0xCC6699
79 | let redComponent = (pink & 0xFF0000) >> 16 // 0xCC
80 | let greenComponent = (pink & 0x00FF00) >> 8 // 0x66
81 | let blueComponent = (pink & 0x0000FF) // 0x99
82 |
83 | //=======================================================
84 | // Overflow Operators
85 | //=======================================================
86 |
87 | // Overflow protection
88 | var potentialOverflow = Int16.max
89 | //potentialOverflow += 1 // throws overflow error
90 |
91 | // Value overflow
92 | var willOverflow = UInt8.max
93 | willOverflow = willOverflow &+ 1
94 |
95 | // Value underflow
96 | var willUnderflow = UInt8.min
97 | willUnderflow = willUnderflow &- 1
98 |
99 | var signedUnderflow = Int8.min
100 | signedUnderflow = signedUnderflow &- 1
101 |
102 | // Division by zero
103 | let x = 1
104 | //let y = x / 0 // throws division by zero error
105 |
106 | //=======================================================
107 | // Precedence and Associativity
108 | //=======================================================
109 |
110 | // Same rules as most languages...when in doubt, add parentheses
111 | 2 + 3 * 4 % 5
112 | 2 + ((3 * 4) % 5)
113 |
114 | //=======================================================
115 | // Operator Functions
116 | //=======================================================
117 |
118 | // Custom arithmetic addition operator
119 | struct Vector2D {
120 | var x = 0.0, y = 0.0
121 | }
122 |
123 | func + (left: Vector2D, right: Vector2D) -> Vector2D {
124 | return Vector2D(x: left.x + right.x, y: left.y + right.y)
125 | }
126 |
127 | let vector = Vector2D(x: 3.0, y: 1.0)
128 | let anotherVector = Vector2D(x: 2.0, y: 4.0)
129 | let combinedVector = vector + anotherVector
130 |
131 | // Prefix and Postfix Operators
132 | prefix func - (vector: Vector2D) -> Vector2D {
133 | return Vector2D(x: -vector.x, y: -vector.y)
134 | }
135 |
136 | let positive = Vector2D(x: 3.0, y: 4.0)
137 | let negative = -positive
138 | let alsoPositive = -negative
139 |
140 | // Compound Assignment Operators
141 | func += (inout left: Vector2D, right: Vector2D) {
142 | left = left + right
143 | }
144 |
145 | var original = Vector2D(x: 1.0, y: 2.0)
146 | let vectorToAdd = Vector2D(x: 3.0, y: 4.0)
147 | original += vectorToAdd
148 |
149 | prefix func ++ (inout vector: Vector2D) -> Vector2D {
150 | vector += Vector2D(x: 1.0, y: 1.0)
151 | return vector
152 | }
153 |
154 | var toIncrement = Vector2D(x: 3.0, y: 4.0)
155 | let afterIncrement = ++toIncrement
156 |
157 | // Equivalence Operators
158 | func == (left: Vector2D, right: Vector2D) -> Bool {
159 | return (left.x == right.x) && (left.y == right.y)
160 | }
161 | func != (left: Vector2D, right: Vector2D) -> Bool {
162 | return !(left == right)
163 | }
164 |
165 | let twoThree = Vector2D(x: 2.0, y: 3.0)
166 | let anotherTwoThree = Vector2D(x: 2.0, y: 3.0)
167 |
168 | if twoThree == anotherTwoThree {
169 | print("These two vectors are equivalent.")
170 | }
171 |
172 | //=======================================================
173 | // Custom Operators
174 | //=======================================================
175 |
176 | prefix operator +++ {}
177 |
178 | prefix func +++ (inout vector: Vector2D) -> Vector2D {
179 | vector += vector
180 | return vector
181 | }
182 |
183 | var toBeDoubled = Vector2D(x: 1.0, y: 4.0)
184 | let afterDoubling = +++toBeDoubled
185 |
186 | // Precedence and Associativity for Custom Infix Operators
187 | infix operator +- { associativity left precedence 140 }
188 |
189 | func +- (left: Vector2D, right: Vector2D) -> Vector2D {
190 | return Vector2D(x: left.x + right.x, y: left.y - right.y)
191 | }
192 |
193 | let firstVector = Vector2D(x: 1.0, y: 2.0)
194 | let secondVector = Vector2D(x: 3.0, y: 4.0)
195 | let plusMinusVector = firstVector +- secondVector
196 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Swift-Introduction
2 | ==================
3 |
4 | This project contains playgrounds and Xcode projects covering all aspects of the new Swift programming language. Each of the sections is based on the Swift Programming Guide provided by Apple with some additional tweaking of my own. This project is intended to be a one-stop-shop for all Swift syntax related questions. Please feel free to add comments and push up pull requests.
5 |
--------------------------------------------------------------------------------