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