Skip to content

Instantly share code, notes, and snippets.

@igavrysh
Last active August 3, 2018 19:29
Show Gist options
  • Save igavrysh/bde82c9c0f6afa000bc822e6569b0dea to your computer and use it in GitHub Desktop.
Save igavrysh/bde82c9c0f6afa000bc822e6569b0dea to your computer and use it in GitHub Desktop.
// Created by Ievgen Gavrysh on 7/30/18.
// http://github.com/igavrysh
//
// This gist is created to show down-to-basics way of handling
// Swift optionals.
//
// No syntax sugar is used and only common and basic Swift language structures
// are applied. That includes but not limited to generics and high order functions.
// I believe that starting learning Swift Optionals from this sample if far
// more correct and easier then with features Apple included into Swift in order to
// make it look 3S language: short, smart and sexy, but also sophisticated.
//
// When Swift novice tries to experiment with "?", "!", "if let", "guard" and "??"
// he scratches his head and asks why let t: Int? = 3 works great and wise versa
// e.g. let t2: Int = t does not, by droping vague error message:
// > Value of optional type 'Int?' not unwrapped; did you mean to use '!' or '?'?
// (⭐️ this script to make me write another one gist explaing exact reason
// why does it happen?)
//
// Be ready to find out the truth about Optional Handling in Swift in lines below
//
// In the Stage 7 you can find a fast and sexy Swift. Definately the great
// way to write and handle Swift Optionals staff as long as you understand
// everything above line 133 and maybe even more
//
// ==================== STAGE 0 - Problem Setup ================================
import Foundation
// Define Coin class
class Coin {
var name: String
var imageName: String
var country: Country
init(name: String, imageName: String, country: Country) {
self.name = name
self.imageName = imageName
self.country = country
}
}
// Define Country class
class Country {
var name: String
var flagImageName: String
init(name: String, flagImageName: String) {
self.name = name
self.flagImageName = flagImageName
}
}
// Make Country print more user-friendly
extension Country: CustomStringConvertible {
var description: String {
return "{country: \(self.name) flagImageName: \(self.flagImageName)}"
}
}
// Make Coin print more user-friendly
extension Coin: CustomStringConvertible {
var description: String {
return "{coin: \(self.name) imageName: \(self.imageName) country: \(country)}"
}
}
// Get Country by name from countries array passed as an argument
// If there is no matched country return nil
// Otherwise return optional wrapped country that matched
func getCountry(named name:String, from counries: Array<Country>)
-> Optional<Country>
{
return counries
.filter({ (country: Country) -> Bool in
return country.name == name
})
.first
}
// ==================== STAGE 1 - Create countries =============================
// Create empty Array of countries that will store Country objects
var countries: Array<Country> = Array<Country>.init()
// Add Ukraine to countries array
countries.append(Country.init(name: "Ukraine", flagImageName: "ukraine_flag"))
// Add the USA to countries array
countries.append(Country.init(name: "USA", flagImageName: "usa_flag"))
// ==================== STAGE 2 - Create coins =================================
// Create empty Array of coins that will store Coin objects
var coins: Array<Coin> = Array<Coin>.init()
// ==================== STAGE 3 - Get "USA"-named country ======================
// Get a countryOptional with the USA name
var countryOptional: Optional<Country> = getCountry(named: "USA", from: countries)
// ==================== STAGE 4 - Create Empty coinOptional ====================
// Create Optional wrapped Coin - coinOptional. Fill it with none value
var coinOptional: Optional<Coin> = Optional<Coin>.none
// ==================== STAGE 5 - Analyze countryOptional ======================
// =========== if it is not empty, then create coin with that country ==========
// =========== if it is empty, then do nothing =================================
// Check if we found a country with a name USA by checking countryOptional value
// * if yes, then unwrap it
// * if no go out of switch with a break statement
switch countryOptional {
// * if we fail to find country with a name of USA go out
case .none:
break
// * if we find country with a name of USA then
case .some(let unwrappedCountry):
// create 25 coint, use found unwrapped country for the name USA
// in coin initialization
coinOptional = Optional<Coin>
.some(
Coin.init(
name: "25_cents",
imageName: "25_cents_usa",
country: unwrappedCountry
)
)
}
// ======= STAGE 6 - Analyze coinOptional created with countryOptional =========
// =========== if it is not empty, then add it to coins array ==================
// =========== if it is empty, then do nothing =================================
// * if we managed to fill coinOptional witn a some Coin value, then add
// unwrapped coin to coins array
// * if we fail to fill coinOptional with a some Coin value, then do nothing
// with break statement
// e.g. just exit switch statement WITHOUT adding any coin to coins array
switch coinOptional {
case .none:
break
case .some(let unwrappedCoin):
coins.append(unwrappedCoin)
}
// ======== STAGE 7 - The fastest way of doing things ============================
// ======== add new coin of America, using Swift syntax sugar ==================
_ = getCountry(named: "USA", from: countries)
.map { Coin(name: "1_cent", imageName: "1_cent_usa", country: $0) }
.map { coins.append($0) }
// ========= STAGE 8 - Print out all coins stored in coins array ===============
print(coins)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment