└── SwiftfulThinkingBasicsBootcamp.playground ├── Pages ├── AccessControl.xcplaygroundpage │ └── Contents.swift ├── Arrays.xcplaygroundpage │ └── Contents.swift ├── BasicTypes.xcplaygroundpage │ └── Contents.swift ├── Classes.xcplaygroundpage │ └── Contents.swift ├── Dictionaries.xcplaygroundpage │ └── Contents.swift ├── Enums.xcplaygroundpage │ └── Contents.swift ├── FilterSortMap.xcplaygroundpage │ └── Contents.swift ├── ForLoops.xcplaygroundpage │ └── Contents.swift ├── Functions.xcplaygroundpage │ └── Contents.swift ├── ObjectOrientedProgramming.xcplaygroundpage │ └── Contents.swift ├── Operators.xcplaygroundpage │ └── Contents.swift ├── Optionals.xcplaygroundpage │ └── Contents.swift ├── Protocols.xcplaygroundpage │ └── Contents.swift ├── Structs.xcplaygroundpage │ └── Contents.swift ├── SwiftBasics.xcplaygroundpage │ └── Contents.swift ├── Tuples.xcplaygroundpage │ └── Contents.swift └── Variables.xcplaygroundpage │ └── Contents.swift ├── contents.xcplayground ├── playground.xcworkspace ├── contents.xcworkspacedata └── xcuserdata │ └── nicksarno.xcuserdatad │ └── UserInterfaceState.xcuserstate └── xcuserdata └── nicksarno.xcuserdatad └── xcschemes └── xcschememanagement.plist /SwiftfulThinkingBasicsBootcamp.playground/Pages/AccessControl.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | // Rule of thumb: 4 | // We want everything to be as private as possible! 5 | // This makes your code easier to read/debug and is good coding practice! 6 | 7 | struct MovieModel { 8 | let title: String 9 | let genre: MovieGenre 10 | private(set) var isFavorite: Bool 11 | 12 | func updateFavoriteStatus(newValue: Bool) -> MovieModel { 13 | MovieModel(title: title, genre: genre, isFavorite: newValue) 14 | } 15 | 16 | mutating func updateFavoriteStatus2(newValue: Bool) { 17 | isFavorite = newValue 18 | } 19 | } 20 | 21 | enum MovieGenre { 22 | case comedy, action, horror 23 | } 24 | 25 | class MovieManager { 26 | 27 | // public 28 | public var movie1 = MovieModel(title: "Avatar", genre: .action, isFavorite: false) 29 | 30 | // private 31 | private var movie2 = MovieModel(title: "Step Brothers", genre: .comedy, isFavorite: false) 32 | 33 | // read is public, set is private 34 | private(set) var movie3 = MovieModel(title: "Avenger", genre: .action, isFavorite: false) 35 | 36 | func updateMovie3(isFavorite: Bool) { 37 | movie3.updateFavoriteStatus2(newValue: isFavorite) 38 | } 39 | } 40 | 41 | 42 | let manager = MovieManager() 43 | 44 | let someValue = manager.movie3 45 | 46 | //manager.movie1 = manager.movie1.updateFavoriteStatus(newValue: true) 47 | //manager.movie3.updateFavoriteStatus2(newValue: true) 48 | manager.updateMovie3(isFavorite: true) 49 | print(manager.movie3) 50 | 51 | 52 | 53 | // Version 1 54 | // We can GET and SET the value from outside the object. 55 | // "too public" 56 | let movie1 = manager.movie1 57 | manager.movie1 = manager.movie1.updateFavoriteStatus(newValue: true) 58 | 59 | 60 | // Version 2 61 | // We can't GET or SET the value from outside the object. 62 | // "cannot access" 63 | //let movie2 = manager.movie2 64 | //manager.movie2 = manager.movie2.updateFavoriteStatus(newValue: true) 65 | 66 | // Version 3 67 | // We can GET the value from outside the object, but we can't SET the value from outside the object. 68 | // "best practice" 69 | let movie3 = manager.movie3 70 | //manager.movie3 = manager.movie3.updateFavoriteStatus(newValue: true) 71 | manager.updateMovie3(isFavorite: true) 72 | 73 | 74 | 75 | // Note: private & public are by far the most common but there are many others 76 | // 77 | // open 78 | // public 79 | // internal 80 | // fileprivate 81 | // private 82 | // 83 | // https://abhimuralidharan.medium.com/swift-3-0-1-access-control-9e71d641a56c 84 | -------------------------------------------------------------------------------- /SwiftfulThinkingBasicsBootcamp.playground/Pages/Arrays.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | 5 | // Arrays, Sets 6 | 7 | 8 | var myTitle: String = "Hello, world!" 9 | var myTitle2: String = "Hello, world!!!" 10 | 11 | // Tuple 12 | 13 | func doSomething(value: (title1: String, title2: String)) { 14 | 15 | } 16 | 17 | doSomething(value: (myTitle, myTitle2)) 18 | 19 | // Custom data model 20 | struct TitlesModel { 21 | let title1: String 22 | let title2: String 23 | } 24 | 25 | func doSomething(value: TitlesModel) { 26 | 27 | } 28 | 29 | doSomething(value: TitlesModel(title1: myTitle, title2: myTitle2)) 30 | 31 | 32 | // -------------------------- 33 | 34 | 35 | let apple: String = "Apple" 36 | let orange: String = "Orange" 37 | 38 | let fruits1: [String] = ["Apple", "Orange"] 39 | let fruits2: [String] = [apple, orange] 40 | let fruits3: Array = [apple, orange] 41 | 42 | let myBools: [Bool] = [true, false, true, true, true, false] 43 | 44 | func doSomething(value: [String]) { 45 | 46 | } 47 | 48 | 49 | var fruitsArray: [String] = ["Apple", "Orange"] 50 | 51 | 52 | let count = fruitsArray.count 53 | let firstItem = fruitsArray.first 54 | let lastItem = fruitsArray.last 55 | 56 | if let firstItem = fruitsArray.first { 57 | // first item 58 | } 59 | 60 | 61 | //fruitsArray = fruitsArray + ["Banana", "Mango"] 62 | 63 | //fruitsArray.append("Banana") 64 | //fruitsArray.append("Mango") 65 | 66 | fruitsArray.append(contentsOf: ["Banana", "Mango"]) 67 | 68 | 69 | // Count = 1, 2, 3, 4 70 | // Indexes = 0, 1, 2, 3 71 | 72 | fruitsArray[0] 73 | 74 | if fruitsArray.indices.contains(4) { 75 | let item = fruitsArray[4] 76 | } 77 | 78 | 79 | let firstIndex = fruitsArray.indices.first 80 | let lastIndex = fruitsArray.indices.last 81 | 82 | 83 | //fruitsArray.append("Watermelon") 84 | 85 | //fruitsArray.insert("Watermelon", at: 2) 86 | fruitsArray.insert(contentsOf: ["Watermelon", "Tangerine"], at: 2) 87 | 88 | if fruitsArray.indices.contains(1) { 89 | fruitsArray.remove(at: 1) 90 | } 91 | 92 | fruitsArray.removeAll() 93 | 94 | print(fruitsArray) 95 | 96 | 97 | struct ProductModel { 98 | let title: String 99 | let price: Int 100 | } 101 | 102 | var myProducts: [ProductModel] = [ 103 | ProductModel(title: "Product 1", price: 50), 104 | ProductModel(title: "Product 2", price: 5), 105 | ProductModel(title: "Product 3", price: 1), 106 | ProductModel(title: "Product 4", price: 50), 107 | ProductModel(title: "Product 5", price: 4), 108 | ProductModel(title: "Product 6", price: 50), 109 | ProductModel(title: "Product 7", price: 2), 110 | ] 111 | 112 | 113 | var finalFruits: [String] = ["Apple", "Orange", "Banana", "Apple"] 114 | 115 | print(finalFruits) 116 | 117 | var fruitsSet: Set = ["Apple", "Orange", "Banana", "Apple"] 118 | 119 | print(fruitsSet) 120 | -------------------------------------------------------------------------------- /SwiftfulThinkingBasicsBootcamp.playground/Pages/BasicTypes.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | // String is "regular text" 4 | let myFirstItem: String = "Hello, world!" 5 | 6 | // Reference previously created objects 7 | let myTitle = myFirstItem 8 | 9 | // Boolean (aka Bool) is true or false 10 | let mySecondItem: Bool = true 11 | let myThirdItem: Bool = false 12 | 13 | // Do not do! 14 | //let myFourthItem: String = "true" 15 | 16 | // Swift is a type-safe language 17 | let myFifthItem: Bool = true 18 | let mySixthItem: String = "Hello, world!" 19 | let mySeventhItem = "Hello, world!" 20 | 21 | // Date 22 | let myFirstDate: Date = Date() 23 | 24 | 25 | // Number can be Int, Double, CGFloat & more 26 | 27 | // Int is a whole Integer 28 | let myFirstNumber: Int = 1 29 | 30 | // Use Double for math 31 | let mySecondNumber: Double = 1.0 32 | 33 | // Use CGFloat for UI 34 | let myThirdNumber: CGFloat = 1.0 35 | -------------------------------------------------------------------------------- /SwiftfulThinkingBasicsBootcamp.playground/Pages/Classes.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | 4 | // Classes are slow! 5 | // Classes are stored in the Heap (memory) 6 | // Objects in the Heap are Reference types 7 | // Reference types point to an object in memory and update the object in memory 8 | 9 | 10 | // All the data needed for some screen 11 | class ScreenViewModel { 12 | let title: String 13 | private(set) var showButton: Bool 14 | 15 | // Same init as a Struct, except structs have implicit inits 16 | init(title: String, showButton: Bool) { 17 | self.title = title 18 | self.showButton = showButton 19 | } 20 | 21 | deinit { 22 | // runs as the object is being removed from memory 23 | // Structs do NOT have deinit! 24 | } 25 | 26 | func hideButton() { 27 | showButton = false 28 | } 29 | 30 | func updateShowButton(newValue: Bool) { 31 | showButton = newValue 32 | } 33 | } 34 | 35 | 36 | // Notice that we are using a "let", because: 37 | // the object itself is not changing 38 | // the data inside the object is changing 39 | let viewModel: ScreenViewModel = ScreenViewModel(title: "Screen 1", showButton: true) 40 | //viewModel.showButton = false 41 | let value = viewModel.showButton 42 | 43 | viewModel.hideButton() 44 | viewModel.updateShowButton(newValue: false) 45 | -------------------------------------------------------------------------------- /SwiftfulThinkingBasicsBootcamp.playground/Pages/Dictionaries.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | var finalFruits: [String] = ["Apple", "Orange", "Banana", "Apple"] 5 | 6 | print(finalFruits) 7 | 8 | let myFruit = finalFruits[1] 9 | 10 | var fruitsSet: Set = ["Apple", "Orange", "Banana", "Apple"] 11 | 12 | print(fruitsSet) 13 | 14 | 15 | var myFirstDictionary: [String : Bool] = [ 16 | "Apple" : true, 17 | "Orange" : false 18 | ] 19 | 20 | 21 | let item = myFirstDictionary["Banana"] 22 | 23 | 24 | 25 | var anotherDictionary: [String : String] = [ 26 | "abc" : "Apple", 27 | "def" : "Banana", 28 | ] 29 | 30 | let item2 = anotherDictionary["abc"] 31 | 32 | anotherDictionary["xyz"] = "Mango" 33 | 34 | anotherDictionary.removeValue(forKey: "def") 35 | 36 | print(anotherDictionary) 37 | 38 | 39 | struct PostModel { 40 | let id: String 41 | let title: String 42 | let likeCount: Int 43 | } 44 | 45 | var postArray: [PostModel] = [ 46 | PostModel(id: "abc123", title: "Post 1", likeCount: 5), 47 | PostModel(id: "def678", title: "Post 2", likeCount: 7), 48 | PostModel(id: "xyz987", title: "Post 3", likeCount: 217), 49 | ] 50 | 51 | if postArray.indices.contains(1) { 52 | let item = postArray[1] 53 | print(item) 54 | } 55 | 56 | var postDict: [String:PostModel] = [ 57 | "abc123" : PostModel(id: "abc123", title: "Post 1", likeCount: 5), 58 | "def678" : PostModel(id: "def678", title: "Post 2", likeCount: 7), 59 | "xyz987" : PostModel(id: "xyz987", title: "Post 3", likeCount: 217), 60 | ] 61 | 62 | let myNewItem = postDict["def678"] 63 | print(myNewItem) 64 | -------------------------------------------------------------------------------- /SwiftfulThinkingBasicsBootcamp.playground/Pages/Enums.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | // Enum is the same as Struct except we know all cases at runtime 4 | 5 | struct CarModel { 6 | let brand: CardBrandOption 7 | let model: String 8 | } 9 | 10 | struct CarBrand { 11 | let title: String 12 | } 13 | 14 | // Enums are stored in memory the same way as a Struct but we cannot mutate them 15 | enum CardBrandOption { 16 | case ford, toyota, honda 17 | 18 | var title: String { 19 | switch self { 20 | case .ford: 21 | return "Ford" 22 | case .toyota: 23 | return "Toyota" 24 | case .honda: 25 | return "Honda" 26 | // default: 27 | // return "Default" 28 | } 29 | } 30 | } 31 | 32 | //var car1: CarModel = CarModel(brand: "Ford", model: "Fiesta") 33 | //var car2: CarModel = CarModel(brand: "Ford", model: "Focus") 34 | //var car3: CarModel = CarModel(brand: "Toyota", model: "Camry") 35 | 36 | 37 | //var brand1 = CarBrand(title: "Ford") 38 | //var brand2 = CarBrand(title: "Toyota") 39 | // 40 | //var car1 = CarModel(brand: brand1, model: "Fiesta") 41 | //var car2 = CarModel(brand: brand1, model: "Focus") 42 | //var car3 = CarModel(brand: brand2, model: "Camry") 43 | 44 | var car1 = CarModel(brand: .ford, model: "Fiesta") 45 | var car2 = CarModel(brand: .ford, model: "Focus") 46 | var car3 = CarModel(brand: .toyota, model: "Camry") 47 | 48 | var fordBrand: CardBrandOption = .ford 49 | 50 | print(fordBrand.title) 51 | -------------------------------------------------------------------------------- /SwiftfulThinkingBasicsBootcamp.playground/Pages/FilterSortMap.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | 4 | struct DatabaseUser { 5 | let name: String 6 | let isPremium: Bool 7 | let order: Int 8 | } 9 | 10 | var allUsers: [DatabaseUser] = [ 11 | DatabaseUser(name: "Nick", isPremium: true, order: 4), 12 | DatabaseUser(name: "Emily", isPremium: false, order: 1), 13 | DatabaseUser(name: "Samantha", isPremium: true, order: 3), 14 | DatabaseUser(name: "Joe", isPremium: true, order: 10000), 15 | DatabaseUser(name: "Chris", isPremium: false, order: 2), 16 | ] 17 | 18 | 19 | //var allPremiumUsers: [DatabaseUser] = allUsers.filter { user in 20 | // if user.isPremium { 21 | // return true 22 | // } 23 | // 24 | // return false 25 | //} 26 | 27 | var allPremiumUsers: [DatabaseUser] = allUsers.filter { user in 28 | user.isPremium 29 | } 30 | 31 | var allPremiumUsers2: [DatabaseUser] = allUsers.filter({ $0.isPremium }) 32 | 33 | 34 | //for user in allUsers { 35 | // if user.isPremium { 36 | // allPremiumUsers.append(user) 37 | // } 38 | //} 39 | //print(allPremiumUsers) 40 | 41 | 42 | var orderedUsers: [DatabaseUser] = allUsers.sorted { user1, user2 in 43 | return user1.order < user2.order 44 | } 45 | 46 | var orderedUsers2: [DatabaseUser] = allUsers.sorted(by: { $0.order < $1.order }) 47 | 48 | print(orderedUsers) 49 | 50 | 51 | var userNames: [String] = allUsers.map { user in 52 | return user.name 53 | } 54 | 55 | var userNames2: [String] = allUsers.map({ $0.name }) 56 | 57 | print(userNames) 58 | -------------------------------------------------------------------------------- /SwiftfulThinkingBasicsBootcamp.playground/Pages/ForLoops.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | // Learn more: 4 | // https://docs.swift.org/swift-book/documentation/the-swift-programming-language/controlflow/#For-In-Loops 5 | 6 | //for x in 0..<50 { 7 | // print(x) 8 | //} 9 | 10 | let myArray = ["Alpha", "Beta", "Gamma", "Delta", "Epsilon"] 11 | 12 | 13 | var secondArray: [String] = [] 14 | 15 | for item in myArray { 16 | print(item) 17 | 18 | if item == "Gamma" { 19 | secondArray.append(item) 20 | } 21 | } 22 | 23 | print(secondArray) 24 | 25 | struct LessonModel { 26 | let title: String 27 | let isFavorite: Bool 28 | } 29 | 30 | let allLessons = [ 31 | LessonModel(title: "Lesson 1", isFavorite: true), 32 | LessonModel(title: "Lesson 2", isFavorite: false), 33 | LessonModel(title: "Lesson 3", isFavorite: false), 34 | LessonModel(title: "Lesson 4", isFavorite: true), 35 | ] 36 | 37 | var favoriteLessons: [LessonModel] = [] 38 | 39 | for lesson in allLessons { 40 | if lesson.isFavorite { 41 | favoriteLessons.append(lesson) 42 | } 43 | } 44 | 45 | print(favoriteLessons) 46 | 47 | 48 | for (index, lesson) in allLessons.enumerated() { 49 | 50 | if index == 1 { 51 | // break 52 | continue 53 | } 54 | 55 | print("index: \(index) || lesson: \(lesson)") 56 | } 57 | -------------------------------------------------------------------------------- /SwiftfulThinkingBasicsBootcamp.playground/Pages/Functions.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | 4 | func myFirstFunction() { 5 | print("MY FIRST FUNCTION CALLED") 6 | mySecondFunction() 7 | myThirdFunction() 8 | } 9 | 10 | func mySecondFunction() { 11 | print("MY SECOND FUNCTION CALLED") 12 | } 13 | 14 | func myThirdFunction() { 15 | print("MY THIRD FUNCTION CALLED") 16 | } 17 | 18 | myFirstFunction() 19 | 20 | 21 | func getUserName() -> String { 22 | let username: String = "Nick" 23 | return username 24 | } 25 | 26 | func checkIfUserIsPremium() -> Bool { 27 | return false 28 | } 29 | 30 | let name: String = getUserName() 31 | 32 | 33 | 34 | // -------------------------------------------- 35 | 36 | showFirstScreen() 37 | 38 | func showFirstScreen() { 39 | var userDidCompleteOnboarding: Bool = false 40 | var userProfileIsCreated: Bool = true 41 | let status = checkUserStatus(didCompleteOnboarding: userDidCompleteOnboarding, profileIsCreated: userProfileIsCreated) 42 | 43 | if status == true { 44 | print("SHOW HOME SCREEN") 45 | } else { 46 | print("SHOW ONBOARDING SCREEN") 47 | } 48 | } 49 | 50 | func checkUserStatus(didCompleteOnboarding: Bool, profileIsCreated: Bool) -> Bool { 51 | if didCompleteOnboarding && profileIsCreated { 52 | return true 53 | } else { 54 | return false 55 | } 56 | } 57 | 58 | func doSomethingElse(someValue: Bool) { 59 | 60 | } 61 | 62 | // ------------------------------------------------------- 63 | 64 | let newValue = doSomething() 65 | 66 | func doSomething() -> String { 67 | var title: String = "Avengers" 68 | 69 | // "If title is equal to Avengers" 70 | if title == "Avengers" { 71 | return "Marvel" 72 | } else { 73 | return "Not Marvel" 74 | } 75 | } 76 | 77 | checkIfTitleIsAvengers() 78 | 79 | 80 | func checkIfTitleIsAvengers() -> Bool { 81 | var title: String = "Avengers" 82 | 83 | // "Make sure title == Avengers 84 | guard title == "Avengers" else { 85 | return false 86 | } 87 | 88 | return true 89 | } 90 | 91 | func checkIfTitleIsAvengers2() -> Bool { 92 | var title: String = "Avengers" 93 | 94 | if title == "Avengers" { 95 | return true 96 | } else { 97 | return false 98 | } 99 | } 100 | 101 | 102 | 103 | // Calculated variables are basically functions 104 | // Generally good for when you don't need to pass data into the function 105 | 106 | let number1 = 5 107 | let number2 = 8 108 | 109 | func calculateNumbers() -> Int { 110 | return number1 + number2 111 | } 112 | 113 | func calculateNumbers(value1: Int, value2: Int) -> Int { 114 | return value1 + value2 115 | } 116 | 117 | let result1 = calculateNumbers() 118 | let result2 = calculateNumbers(value1: number1, value2: number2) 119 | 120 | var calculatedNumber: Int { 121 | return number1 + number2 122 | } 123 | -------------------------------------------------------------------------------- /SwiftfulThinkingBasicsBootcamp.playground/Pages/ObjectOrientedProgramming.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | 4 | /* 5 | 6 | // Object Oriented Programming 7 | 8 | // During the life the app, we create and destroy objects 9 | // Create = Initialize (init) = Allocate (add to memory) 10 | // Destroy = Deinitialize (deinit) = Deallocate (remove from memory) 11 | 12 | // Automatic Reference Counting (ARC) 13 | // A live count of the number of objects in memory 14 | // Create 1 object, count goes up by 1 15 | // Create 2 objects, count goes up by 2 16 | // Destroy 1 object, count goes down by 1 17 | 18 | // The more objects in memory, the slower the app performs 19 | // We want to keep the ARC count as low as possible 20 | // We want to create objects only when we need them 21 | // And destory them as soon as we no longer need them 22 | 23 | // For example, if an app has 2 screens and user is moving from screen 1 to screen 2. We only want to allocate screen 2 WHEN we need it (ie. when the user clicks a button to segue to screen 2). When we get to screen 2, we may want to deallocate screen 1. 24 | 25 | 26 | // There are 2 types of Memory 27 | // Stack & Heap 28 | // Only objects in the Heap are counted towards ARC 29 | 30 | 31 | // Advanced info here: 32 | // https://www.youtube.com/watch?v=-JLenSTKEcA&themeRefresh=1 33 | 34 | 35 | // Objects in the Stack 36 | // String, Bool, Int, most basic types 37 | // NEW: Struct, Enum, Array 38 | 39 | // Objects in the Heap 40 | // Functions 41 | // NEW: Class, Actors 42 | 43 | 44 | // iPhone is a "multi-threaded environment" 45 | // There are multiple "threads" or "engines" running simultaneously 46 | // Each threads has a Stack 47 | // But there is only 1 Heap for all threads 48 | 49 | // Therefore: 50 | // Stack is faster, lower memory footprint, preferable 51 | // Heap is slower, higher memory footprint, risk of threading issues 52 | 53 | 54 | // Value vs Reference types 55 | 56 | // Objects in the Stack are "Value" types. 57 | // When you edit a Value type, you create a copy of it with new data. 58 | 59 | // Objects in the Heap are "Reference" types. 60 | // When you edit a Reference type, you edit the object that you are referencing. This "reference" is called "pointer" because it "points" to an object in the Heap (in memory). 61 | 62 | */ 63 | 64 | 65 | struct MyFirstObject { 66 | let title: String = "Hello, world!" 67 | } 68 | 69 | class MySecondObject { 70 | let title: String = "Hello, world!" 71 | } 72 | 73 | 74 | // Class vs Struct explained to a 5-year old 75 | 76 | // Imagine a school and in the school there are classrooms. 77 | // Within each class, there are quizzes. 78 | // During the day, the teacher will hand out many different quizzes to different classes. The students will answer the quizzes and return them back to the teacher. 79 | 80 | // "school" = App 81 | // "classroom" = Class 82 | // "quiz" = Struct 83 | 84 | // In this example, we have a classroom and there are many actions that occur inside the classroom. 85 | // In code, we create a class and can perform actions within the class. 86 | 87 | // In this example, there are many different types of quizzes. The teacher hands out the quizzes and the students take the quizzes and return them to the teacher. 88 | // In code, we create many structs and pass them around out app with ease. 89 | 90 | // Note: 91 | // This metaphor is NOT perfect :) 92 | // Technical a "quiz" can be a class, etc. 93 | 94 | 95 | // We want to use a class for things like: 96 | // "Manager" "DataService" "Service" "Factory" "ViewModel" 97 | // Objects that we create and want to perform actions inside. 98 | 99 | // We want to use a struct for things like: 100 | // Data models 101 | // Objects that we create and pass around our app. 102 | -------------------------------------------------------------------------------- /SwiftfulThinkingBasicsBootcamp.playground/Pages/Operators.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | //var likeCount: Double = 5 4 | //var commentCount: Double = 0 5 | //var viewCount: Double = 100 6 | 7 | //likeCount = 5 + 1 8 | 9 | // Addition 10 | //likeCount = likeCount + 1 11 | //likeCount += 1 12 | 13 | // Subtraction 14 | //likeCount = likeCount - 1 15 | //likeCount -= 1 16 | 17 | // Multiplication 18 | //likeCount = likeCount * 1.5 19 | //likeCount *= 1.5 20 | 21 | // Division 22 | //likeCount = likeCount / 2 23 | //likeCount /= 2 24 | 25 | // Order of operations does matter! 26 | // PEMDAS 27 | //likeCount = likeCount - 1 * 1.5 28 | //likeCount = (likeCount - 1) * 1.5 29 | 30 | 31 | var likeCount: Double = 5 32 | var commentCount: Double = 0 33 | var viewCount: Double = 100 34 | 35 | likeCount -= 1 36 | 37 | print(likeCount) 38 | 39 | if likeCount == 5 { 40 | print("Post has 5 likes.") 41 | } else { 42 | print("Post does NOT have 5 likes.") 43 | } 44 | 45 | if likeCount != 5 { 46 | print("Post does NOT have 5 likes.") 47 | } 48 | 49 | if likeCount > 5 { 50 | print("Post has greater than 5 likes.") 51 | } 52 | 53 | if likeCount >= 5 { 54 | print("Post has greater than or equal to 5 likes.") 55 | } 56 | 57 | if likeCount < 5 { 58 | print("Post has less than 5 likes.") 59 | } 60 | 61 | if likeCount <= 5 { 62 | print("Post has less than or equal to 5 likes.") 63 | } 64 | 65 | if (likeCount > 3) && (commentCount > 0) { 66 | print("Post has greater than 3 likes AND greater than 0 comments.") 67 | } else { 68 | print("Post has 3 or less likes OR post has 0 or less comments.") 69 | } 70 | 71 | if likeCount > 3 || commentCount > 0 { 72 | print("Post has greater than 3 likes OR greater than 0 comments.") 73 | } else { 74 | print("Post has 3 or less likes AND post has 0 or less comments.") 75 | } 76 | 77 | var userIsPremium: Bool = true 78 | var userIsNew: Bool = false 79 | 80 | if userIsPremium && userIsNew { 81 | 82 | } 83 | 84 | 85 | if (likeCount > 3 && commentCount > 0) || (viewCount > 50) { 86 | print("EXECUTE") 87 | } 88 | 89 | if (likeCount > 100) && (commentCount > 0 || viewCount > 50) { 90 | print("EXECUTE") 91 | } 92 | 93 | if likeCount > 5 || userIsPremium { 94 | 95 | } 96 | 97 | 98 | if likeCount > 5 { 99 | print("Like count > 5") 100 | } else if likeCount > 2 { 101 | print("Like count > 2") 102 | } else if userIsPremium { 103 | print("user is premium") 104 | } else { 105 | print("else statement") 106 | } 107 | -------------------------------------------------------------------------------- /SwiftfulThinkingBasicsBootcamp.playground/Pages/Optionals.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | 4 | 5 | 6 | // "There is always a value and it is a Boolean" 7 | let myBool: Bool = false 8 | 9 | // "We don't know if there is a value, but if there is, it is a Boolean" 10 | var myOtherBool: Bool? = nil 11 | 12 | //print(myOtherBool) 13 | //myOtherBool = true 14 | //print(myOtherBool) 15 | //myOtherBool = false 16 | //print(myOtherBool) 17 | //myOtherBool = nil 18 | //print(myOtherBool) 19 | 20 | // nil coalescing operator 21 | 22 | let newValue: Bool? = myOtherBool 23 | 24 | // "The value of myOtherBool (if there is one), otherwise false" 25 | let newValue2: Bool = myOtherBool ?? false 26 | 27 | print("New value 2: \(newValue2.description)") 28 | 29 | var myString: String? = "Hello, world!" 30 | 31 | print(myString ?? "There is no value!") 32 | 33 | myString = "New text!" 34 | print(myString ?? "There is no value!") 35 | 36 | myString = nil 37 | 38 | print(myString ?? "There is no value!") 39 | 40 | //let newString = myString ?? "some default value" 41 | 42 | 43 | // --------------------------------------------------- 44 | 45 | 46 | var userIsPremium: Bool? = nil 47 | 48 | func checkIfUserIsPremium() -> Bool? { 49 | return userIsPremium 50 | } 51 | 52 | func checkIfUserIsPremium2() -> Bool { 53 | return userIsPremium ?? false 54 | } 55 | 56 | 57 | let isPremium = checkIfUserIsPremium2() 58 | 59 | 60 | // If-let 61 | // When if-let is successful, enter the closure 62 | func checkIfUserIsPremium3() -> Bool { 63 | 64 | // If there is a value, let newValue equal that value 65 | if let newValue = userIsPremium { 66 | // Here we have access to the non-optional value 67 | return newValue 68 | } else { 69 | return false 70 | } 71 | } 72 | 73 | func checkIfUserIsPremium4() -> Bool { 74 | if let newValue = userIsPremium { 75 | return newValue 76 | } 77 | 78 | return false 79 | } 80 | 81 | func checkIfUserIsPremium5() -> Bool { 82 | if let userIsPremium { 83 | return userIsPremium 84 | } 85 | 86 | return false 87 | } 88 | 89 | // Guard 90 | // When a guard is a failure, enter the closure 91 | func checkIfUserIsPremium6() -> Bool { 92 | 93 | // Make sure there is a value 94 | // If there is, let newValue equal that value 95 | // Else (otherwise) return out of the function 96 | guard let newValue = userIsPremium else { 97 | return false 98 | } 99 | 100 | // Here we have access to the non-optional value 101 | return newValue 102 | } 103 | 104 | func checkIfUserIsPremium7() -> Bool { 105 | guard let userIsPremium else { 106 | return false 107 | } 108 | 109 | return userIsPremium 110 | } 111 | 112 | 113 | // --------------------------------------------------- 114 | 115 | 116 | var userIsNew: Bool? = true 117 | var userDidCompleteOnboarding: Bool? = false 118 | var userFavoriteMovie: String? = nil 119 | 120 | 121 | func checkIfUserIsSetUp() -> Bool { 122 | 123 | if let userIsNew, let userDidCompleteOnboarding, let userFavoriteMovie { 124 | // userIsNew == Bool AND 125 | // userDidCompleteOnboarding == Bool AND 126 | // userFavoriteMovie == String 127 | return getUserStatus( 128 | userIsNew: userIsNew, 129 | userDidCompleteOnboarding: userDidCompleteOnboarding, 130 | userFavoriteMovie: userFavoriteMovie 131 | ) 132 | } else { 133 | // userIsNew == nil OR 134 | // userDidCompleteOnboarding == nil OR 135 | // userFavoriteMovie == nil 136 | return false 137 | } 138 | } 139 | 140 | 141 | func checkIfUserIsSetUp2() -> Bool { 142 | 143 | guard let userIsNew, let userDidCompleteOnboarding, let userFavoriteMovie else { 144 | // userIsNew == nil OR 145 | // userDidCompleteOnboarding == nil OR 146 | // userFavoriteMovie == nil 147 | return false 148 | } 149 | 150 | // userIsNew == Bool AND 151 | // userDidCompleteOnboarding == Bool AND 152 | // userFavoriteMovie == String 153 | return getUserStatus( 154 | userIsNew: userIsNew, 155 | userDidCompleteOnboarding: userDidCompleteOnboarding, 156 | userFavoriteMovie: userFavoriteMovie 157 | ) 158 | } 159 | 160 | func getUserStatus(userIsNew: Bool, userDidCompleteOnboarding: Bool, userFavoriteMovie: String) -> Bool { 161 | if userIsNew && userDidCompleteOnboarding { 162 | return true 163 | } 164 | 165 | return false 166 | } 167 | 168 | 169 | // layered if-let 170 | func checkIfUserIsSetUp3() -> Bool { 171 | if let userIsNew { 172 | // userIsNew == Bool 173 | 174 | if let userDidCompleteOnboarding { 175 | // userDidCompleteOnboarding == Bool 176 | 177 | if let userFavoriteMovie { 178 | // userFavoriteMovie == String 179 | return getUserStatus( 180 | userIsNew: userIsNew, 181 | userDidCompleteOnboarding: userDidCompleteOnboarding, 182 | userFavoriteMovie: userFavoriteMovie 183 | ) 184 | } else { 185 | // userFavoriteMovie == nil 186 | return false 187 | } 188 | 189 | } else { 190 | // userDidCompleteOnboarding == nil 191 | return false 192 | } 193 | } else { 194 | // userIsNew == nil 195 | return false 196 | } 197 | } 198 | 199 | 200 | // layered guard 201 | func checkIfUserIsSetUp4() -> Bool { 202 | guard let userIsNew else { 203 | // userIsNew == nil 204 | return false 205 | } 206 | // userIsNew == Bool 207 | 208 | guard let userDidCompleteOnboarding else { 209 | // userDidCompleteOnboarding == nil 210 | return false 211 | } 212 | // userDidCompleteOnboarding == Bool 213 | 214 | guard let userFavoriteMovie else { 215 | // userFavoriteMovie == nil 216 | return false 217 | } 218 | // userFavoriteMovie == String 219 | 220 | return getUserStatus( 221 | userIsNew: userIsNew, 222 | userDidCompleteOnboarding: userDidCompleteOnboarding, 223 | userFavoriteMovie: userFavoriteMovie 224 | ) 225 | } 226 | 227 | func checkIfUserIsSetUp5() -> Bool { 228 | guard let userIsNew else { 229 | return false 230 | } 231 | 232 | guard let userDidCompleteOnboarding else { 233 | return false 234 | } 235 | 236 | guard let userFavoriteMovie else { 237 | return false 238 | } 239 | 240 | return getUserStatus( 241 | userIsNew: userIsNew, 242 | userDidCompleteOnboarding: userDidCompleteOnboarding, 243 | userFavoriteMovie: userFavoriteMovie 244 | ) 245 | } 246 | 247 | // Optional chaining 248 | 249 | func getUsername() -> String? { 250 | return "test" 251 | } 252 | 253 | func getTitle() -> String { 254 | return "title" 255 | } 256 | 257 | func getUserData() { 258 | 259 | 260 | let username: String? = getUsername() 261 | 262 | // "I will get the count if the username is not nil" 263 | let count: Int? = username?.count 264 | 265 | let title: String = getTitle() 266 | 267 | // "I will get the count always" 268 | let count2 = title.count 269 | 270 | 271 | 272 | // If username has a value, and first character in username has a value, then return the value of isLowercase 273 | // Optional chaining 274 | let firstCharacterIsLowercased = username?.first?.isLowercase ?? false 275 | 276 | // "If will get the count because I know 100% that username is not nil" 277 | // This will crash your application if username is nil! 278 | let count3: Int = username!.count 279 | 280 | } 281 | 282 | // safely unwrap an optional 283 | // nil coalscing 284 | // if-let 285 | // guard 286 | 287 | 288 | // explicitly unwrap optional 289 | // ! 290 | -------------------------------------------------------------------------------- /SwiftfulThinkingBasicsBootcamp.playground/Pages/Protocols.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | struct EmployeeModel: EmployeeHasAName { 4 | let title: String 5 | let name: String 6 | } 7 | 8 | protocol EmployeeHasAName { 9 | let name: String 10 | } 11 | -------------------------------------------------------------------------------- /SwiftfulThinkingBasicsBootcamp.playground/Pages/Structs.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | 4 | // Structs are fast! 5 | // Structs are stored in the Stack (memory) 6 | // Objects in the Stack are Value types 7 | // Value types are copied & mutated 8 | 9 | 10 | struct Quiz { 11 | let title: String 12 | let dateCreated: Date 13 | let isPremium: Bool? 14 | 15 | // Structs have an implicit init 16 | // init(title: String, dateCreated: Date) { 17 | // self.title = title 18 | // self.dateCreated = dateCreated 19 | // } 20 | 21 | // init(title: String, dateCreated: Date = .now) { 22 | // self.title = title 23 | // self.dateCreated = dateCreated 24 | // } 25 | 26 | init(title: String, dateCreated: Date?, isPremium: Bool?) { 27 | self.title = title 28 | self.dateCreated = dateCreated ?? .now 29 | self.isPremium = isPremium 30 | } 31 | } 32 | 33 | 34 | let myObject: String = "Hello, world!" 35 | 36 | //let myQuiz: Quiz = Quiz(title: "Quiz 1", dateCreated: .now) 37 | //let myQuiz: Quiz = Quiz(title: "Quiz 1") 38 | //let myQuiz = Quiz(title: "Quiz 1", isPremium: nil) 39 | let myQuiz: Quiz = Quiz(title: "Quiz 1", dateCreated: nil, isPremium: false) 40 | 41 | print(myQuiz.title) 42 | 43 | 44 | // ----------------------------------------------------- 45 | 46 | 47 | // "Immutable struct" = all "let" constants = NOT mutable = "cannot mutate it!" 48 | struct UserModel { 49 | let name: String 50 | let isPremium: Bool 51 | } 52 | 53 | var user1: UserModel = UserModel(name: "Nick", isPremium: false) 54 | 55 | func markUserAsPremium() { 56 | print(user1) 57 | user1 = UserModel(name: user1.name, isPremium: true) 58 | print(user1) 59 | } 60 | 61 | //markUserAsPremium() 62 | 63 | // ----------------------------------------------------- 64 | 65 | // "mutable struct" 66 | struct UserModel2 { 67 | let name: String 68 | var isPremium: Bool 69 | } 70 | 71 | var user2 = UserModel2(name: "Nick", isPremium: false) 72 | 73 | func markUserAsPremium2() { 74 | print(user2) 75 | 76 | // "mutate" the struct 77 | user2.isPremium = true 78 | 79 | print(user2) 80 | } 81 | markUserAsPremium2() 82 | 83 | // ----------------------------------------------------- 84 | 85 | // "immutable struct" 86 | struct UserModel3 { 87 | let name: String 88 | let isPremium: Bool 89 | 90 | func markUserAsPremium(newValue: Bool) -> UserModel3 { 91 | UserModel3(name: name, isPremium: newValue) 92 | } 93 | } 94 | 95 | var user3: UserModel3 = UserModel3(name: "Nick", isPremium: false) 96 | user3 = user3.markUserAsPremium(newValue: true) 97 | 98 | // ----------------------------------------------------- 99 | 100 | // "mutable struct" 101 | 102 | struct UserModel4 { 103 | let name: String 104 | private(set) var isPremium: Bool 105 | 106 | mutating func markUserAsPremium() { 107 | isPremium = true 108 | } 109 | 110 | mutating func updateIsPremium(newValue: Bool) { 111 | isPremium = newValue 112 | } 113 | } 114 | 115 | var user4 = UserModel4(name: "Nick", isPremium: false) 116 | user4.markUserAsPremium() 117 | user4.updateIsPremium(newValue: true) 118 | 119 | 120 | struct User5 { 121 | let name: String 122 | let isPremium: Bool 123 | let isNew: Bool 124 | // 125 | // 126 | // 127 | // 128 | } 129 | -------------------------------------------------------------------------------- /SwiftfulThinkingBasicsBootcamp.playground/Pages/SwiftBasics.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | var greeting = "Hello, playground" 4 | 5 | print(greeting) 6 | print(greeting) 7 | print(greeting) 8 | print(greeting) 9 | print(greeting) 10 | 11 | 12 | // This is a single-line comment 13 | 14 | // These are multiple single-line comments 15 | // This is a comment 16 | // and this is some more info 17 | 18 | /* 19 | This is a multi-line comment 20 | that goes to 21 | mutliple lines! 22 | */ 23 | 24 | 25 | // Naming Conventions 26 | 27 | // Camel Case - CORRECT! 28 | // The first word is lowercased and then the first character in every following word is uppercased. 29 | 30 | let firstGreeting = "Hello, world!" 31 | let thisIsMyFirstGreeting = "Hello, world!" 32 | 33 | // wrong 34 | let thisismysecondgreeting = "Hello, world!" 35 | 36 | // Snake Case - wrong 37 | let this_is_what_snake_case_looks_like = "Hello, world!" 38 | 39 | // Pascal Case - wrong 40 | let ThisIsWhatPascalCaseLooksLike = "Hello, world!" 41 | 42 | // Camel Case - right 43 | let thisIsWhatCamelCaseLooksLike = "Hello, world!" 44 | -------------------------------------------------------------------------------- /SwiftfulThinkingBasicsBootcamp.playground/Pages/Tuples.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | 4 | 5 | 6 | var userName: String = "Hello" 7 | var userIsPremium: Bool = false 8 | var userIsNew: Bool = true 9 | 10 | func getUserName() -> String { 11 | userName 12 | } 13 | func getUserIsPremium() -> Bool { 14 | userIsPremium 15 | } 16 | 17 | // limited to 1 return type 18 | func getUserInfo() -> String { 19 | 20 | let name = getUserName() 21 | let isPremium = getUserIsPremium() 22 | 23 | return name 24 | } 25 | 26 | // tuple can combine multiple pieces of data 27 | func getUserInfo2() -> (String, Bool) { 28 | let name = getUserName() 29 | let isPremium = getUserIsPremium() 30 | 31 | return (name, isPremium) 32 | } 33 | 34 | var userData1: String = userName 35 | var userData2: (String, Bool, Bool) = (userName, userIsPremium, userIsNew) 36 | 37 | 38 | let info1 = getUserInfo2() 39 | let name1: String = info1.0 40 | 41 | func getUserInfo3() -> (name: String, isPremium: Bool) { 42 | let name = getUserName() 43 | let isPremium = getUserIsPremium() 44 | 45 | return (name, isPremium) 46 | } 47 | 48 | let info2 = getUserInfo3() 49 | let name2 = info2.name 50 | 51 | func getUserInfo4() -> (name: String, isPremium: Bool, isNew: Bool) { 52 | return (userName, userIsPremium, userIsNew) 53 | } 54 | 55 | func doSomethingWithUserInfo(info: (name: String, isPremium: Bool, isNew: Bool)) { 56 | 57 | } 58 | 59 | 60 | let info = getUserInfo4() 61 | doSomethingWithUserInfo(info: info) 62 | -------------------------------------------------------------------------------- /SwiftfulThinkingBasicsBootcamp.playground/Pages/Variables.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | 4 | // Constant 5 | let someConstant: Bool = true 6 | 7 | // Variable 8 | var someVariable: Bool = true 9 | 10 | // Cannot assign to value: 'someConstant' is a 'let' constant 11 | // someConstant = false 12 | 13 | someVariable = false 14 | 15 | var myNumber: Double = 1.1234 16 | print(myNumber) 17 | myNumber = 2 18 | print(myNumber) 19 | myNumber = 234870234 20 | print(myNumber) 21 | myNumber = 1 22 | print(myNumber) 23 | myNumber = 458 24 | 25 | 26 | // if statements 27 | 28 | var userIsPremium: Bool = false 29 | 30 | if userIsPremium == true { 31 | print("1 - user is premium") 32 | } else { 33 | print("1.1 - user is NOT premium") 34 | } 35 | 36 | if userIsPremium { 37 | print("2 - user is premium") 38 | } 39 | 40 | if userIsPremium == false { 41 | print("3 - user is NOT premium") 42 | } 43 | 44 | if !userIsPremium { 45 | print("4 - user is NOT premium") 46 | } 47 | -------------------------------------------------------------------------------- /SwiftfulThinkingBasicsBootcamp.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /SwiftfulThinkingBasicsBootcamp.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SwiftfulThinkingBasicsBootcamp.playground/playground.xcworkspace/xcuserdata/nicksarno.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SwiftfulThinking/Swift-Basics/d86c9a465598b29eb5ab89ade0f7763aeca96301/SwiftfulThinkingBasicsBootcamp.playground/playground.xcworkspace/xcuserdata/nicksarno.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /SwiftfulThinkingBasicsBootcamp.playground/xcuserdata/nicksarno.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | SwiftfulThinkingBasicsBootcamp (Playground).xcscheme 8 | 9 | isShown 10 | 11 | orderHint 12 | 0 13 | 14 | 15 | 16 | 17 | --------------------------------------------------------------------------------