-
Notifications
You must be signed in to change notification settings - Fork 4
Swift Xcode
Cmd 0: hide/show left panel
Cmd 1: show project navigator
Cmd Option 0: hide/show right panel
Option left-click a file: Open file side by side
Cmd Shift F: Search within file / file name
Cmd Shift O: Open file
Option left-click a variable: Check its type
let greeting = "Hello world!"
let firstChar = greeting[greeting.startIndex] // 'H'
let secondCharIndex = greeting.index(greeting.startIndex, offsetBy: 1)
let secondChar = greeting[secondCharIndex] //'e'
let lastCharIndex = greeting.index(before: greeting.endIndex)
let lastChar = greeting[lastCharIndex] //'!'
let secondLastCharIndex = greeting.index(greeting.endIndex, offsetBy: -2)
let secondLastChar = greeting[secondLastCharIndex] //'d'
var welcome = "hello"
welcome.insert("!", at: welcome.endIndex)
// welcome now equals "hello!"
welcome.insert(contentsOf: " there", at: welcome.index(before: welcome.endIndex))
// welcome now equals "hello there!"
welcome.remove(at: welcome.index(before: welcome.endIndex))
// welcome now equals "hello there"
let range = welcome.index(welcome.endIndex, offsetBy: -6)..<welcome.endIndex
welcome.removeSubrange(range)
// welcome now equals "hello"
let greeting2 = "Hello,world!"
let index = greeting2.firstIndex(of: ",") ?? greeting2.endIndex
let excludeIndexSubstring = greeting2[..<index] //"Hello" of type String.SubSequence
let includeIndexSubstring = greeting2[...index] //"Hello," of type String.SubSequence
let newString = String(excludeIndexSubstring) //"Hello" of type String
var someInts = [Int]()
someInts.append(3)
var threeDoubles = Array(repeating: 0.0, count: 3)
// threeDoubles is of type [Double], and equals [0.0, 0.0, 0.0]
var anotherThreeDoubles = Array(repeating: 2.5, count: 3)
// anotherThreeDoubles is of type [Double], and equals [2.5, 2.5, 2.5]
var sixDoubles = threeDoubles + anotherThreeDoubles
// sixDoubles is inferred as [Double], and equals [0.0, 0.0, 0.0, 2.5, 2.5, 2.5]
var shoppingList = ["Eggs", "Milk"]
shoppingList += ["Baking Powder"]
shoppingList += ["Chocolate Spread", "Cheese", "Butter"]
shoppingList.insert("Maple Syrup", at: 0)
let mapleSyrup = shoppingList.remove(at: 0)
let apples = shoppingList.removeLast()
for item in shoppingList {
print(item)
}
for (index, value) in shoppingList.enumerated() {
print("Item \(index + 1): \(value)")
}
A type must be hashable in order to be stored in a set
var letters = Set<Character>()
let count = letters.count
let isEmpty = letters.isEmpty
letters.insert("a")
letters = [] // letters is now an empty set, but is still of type Set<Character>
var favoriteGenres: Set<String> = ["Rock", "Classical", "Hip hop"]
var favoriteGenres2: Set = ["Rock", "Classical", "Hip hop"] //Simpler than above line
let removedGenre = favoriteGenres.remove("Rock")
let contains = favoriteGenres.contains("Funk")
for genre in favoriteGenres.sorted() {
print("\(genre)")
}
let oddDigits: Set = [1, 3, 5, 7, 9]
let evenDigits: Set = [0, 2, 4, 6, 8]
let singleDigitPrimeNumbers: Set = [2, 3, 5, 7]
oddDigits.union(evenDigits).sorted() // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
oddDigits.intersection(evenDigits).sorted() // []
oddDigits.subtracting(singleDigitPrimeNumbers).sorted() // [1, 9]
oddDigits.symmetricDifference(singleDigitPrimeNumbers).sorted() // [1, 2, 9]
let houseAnimals: Set = ["🐶", "🐱"]
let farmAnimals: Set = ["🐮", "🐔", "🐑", "🐶", "🐱"]
let cityAnimals: Set = ["🐦", "🐭"]
houseAnimals.isSubset(of: farmAnimals) // true
farmAnimals.isSuperset(of: houseAnimals) // true
farmAnimals.isDisjoint(with: cityAnimals) // true. To determine whether two sets have no values in common.
A dictionary Key type must conform to the Hashable protocol, like a set’s value type.
var namesOfIntegers = [Int: String]()
namesOfIntegers[16] = "sixteen"
namesOfIntegers = [:] // namesOfIntegers is once again an empty dictionary of type [Int: String]
let count = namesOfIntegers.count
let isEmpty = namesOfIntegers.isEmpty
var airports: [String: String] = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
var airports2 = ["YYZ": "Toronto Pearson", "DUB": "Dublin"] //Simpler format than above line
airports["LHR"] = "London"
let oldValue = airports.updateValue("Dublin Airport", forKey: "DUB") //oldValue is of type string?
airports["APL"] = nil //Remove a key-value pair
let removedValue = airports.removeValue(forKey: "DUB") //Another way to remove a key-value pair
for (airportCode, airportName) in airports {
print("\(airportCode): \(airportName)")
}
for airportCode in airports.keys {
print("Airport code: \(airportCode)")
}
for airportName in airports.values {
print("Airport name: \(airportName)")
}
let airportCodes = [String](airports.keys) // airportCodes is ["LHR", "YYZ"]
let airportNames = [String](airports.values) // airportNames is ["London Heathrow", "Toronto Pearson"]
// Open range (i.e. not include 60)
let minuteInterval = 5
let minutes = 60
for tickMark in stride(from: 0, to: minutes, by: minuteInterval) {
print (tickMark)// render the tick mark every 5 minutes (0, 5, 10, 15 ... 45, 50, 55)
}
//Close range (i.e. include 12)
let hours = 12
let hourInterval = 3
for tickMark in stride(from: 3, through: hours, by: hourInterval) {
print (tickMark)
}
var a = 0
var b = 5
while a < b {
print (a)
if a == 3 {
break
}
a += 1
}
a = 0
repeat {
print (a)
a += 1
}while a < b
switch statements in Swift do not fall through the bottom of each case and into the next one by default.
let approximateCount = 62
let countedThings = "moons orbiting Saturn"
let naturalCount: String
switch approximateCount {
case -1: fallthrough
case 0:
naturalCount = "no"
case 1..<5:
naturalCount = "a few"
case 5..<12:
naturalCount = "several"
case 12..<100:
naturalCount = "dozens of"
case 100..<1000:
naturalCount = "hundreds of"
default:
naturalCount = "many"
}
print("There are \(naturalCount) \(countedThings).")
Tuple
let somePoint = (1, 1)
switch somePoint {
case (0, 0):
print("\(somePoint) is at the origin")
case (_, 0):
print("\(somePoint) is on the x-axis")
case (0, _):
print("\(somePoint) is on the y-axis")
case (-2...2, -2...2):
print("\(somePoint) is inside the box")
default:
print("\(somePoint) is outside of the box")
}
// Prints "(1, 1) is inside the box"
Tuple let
let anotherPoint = (2, 0)
switch anotherPoint {
case (let x, 0):
print("on the x-axis with an x value of \(x)")
case (0, let y):
print("on the y-axis with a y value of \(y)")
case (let x, let y):
print("somewhere else at (\(x), \(y))")
}
where
let yetAnotherPoint = (1, -1)
switch yetAnotherPoint {
case let (x, y) where x == y:
print("(\(x), \(y)) is on the line x == y")
case let (x, y) where x == -y:
print("(\(x), \(y)) is on the line x == -y")
case let (x, y):
print("(\(x), \(y)) is just some arbitrary point")
}
label name: while condition {
statements
}
guard always has an else clause
func greet(person: [String: String]) {
guard let name = person["name"] else {
return
}
print("Hello \(name)!")
guard let location = person["location"] else {
print("I hope the weather is nice near you.")
return
}
print("I hope the weather is nice in \(location).")
}
greet(person: ["name": "John"])
// Prints "Hello John!"
// Prints "I hope the weather is nice near you."
greet(person: ["name": "Jane", "location": "Cupertino"])
// Prints "Hello Jane!"
// Prints "I hope the weather is nice in Cupertino."
if #available(iOS 10, macOS 10.12, *) {
// Use iOS 10 APIs on iOS, and use macOS 10.12 APIs on macOS
} else {
// Fall back to earlier iOS and macOS APIs
}
func greet(p person: String) -> String {
return "Hello, " + person + "!"
}
print(greet(p : "Anna"))
func greeting(_ person: String) -> String {
return "Hello, " + person + "!"
}
print (greeting("Tom"))
func minMax(array: [Int]) -> (min: Int, max: Int) {
var currentMin = array[0]
var currentMax = array[0]
for value in array[1..<array.count] {
if value < currentMin {
currentMin = value
} else if value > currentMax {
currentMax = value
}
}
return (currentMin, currentMax)
}
let bounds = minMax(array: [8, -6, 2, 109, 3, 71])
print("min is \(bounds.min) and max is \(bounds.max)")
func minMax(array: [Int]) -> (min: Int, max: Int)? {
if array.isEmpty { return nil }
var currentMin = array[0]
var currentMax = array[0]
for value in array[1..<array.count] {
if value < currentMin {
currentMin = value
} else if value > currentMax {
currentMax = value
}
}
return (currentMin, currentMax)
}
if let bounds = minMax(array : [Int]()) {
print("min is \(bounds.min) and max is \(bounds.max)")
}else{
print("Array is empty")
}
func someFunction(parameterWithoutDefault: Int, parameterWithDefault: Int = 12) {
print ("\(parameterWithoutDefault), \(parameterWithDefault)")
}
someFunction(parameterWithoutDefault: 3, parameterWithDefault: 6) // parameterWithDefault is 6
someFunction(parameterWithoutDefault: 4)
func arithmeticMean(_ numbers: Double...) -> Double {
var total: Double = 0
for number in numbers {
total += number
}
return total / Double(numbers.count)
}
arithmeticMean(1, 2, 3, 4, 5) // returns 3.0, which is the arithmetic mean of these five numbers
arithmeticMean(3, 8.25, 18.75) // returns 10.0, which is the arithmetic mean of these three numbers
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
let temporaryA = a
a = b
b = temporaryA
}
var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
print("someInt is now \(someInt), and anotherInt is now \(anotherInt)") // Prints "someInt is now 107, and anotherInt is now 3"
func addTwoInts(_ a: Int, _ b: Int) -> Int {
return a + b
}
func multiplyTwoInts(_ a: Int, _ b: Int) -> Int {
return a * b
}
var mathFunction: (Int, Int) -> Int = addTwoInts
print("Result: \(mathFunction(2, 3))") // Prints "Result: 5"
mathFunction = multiplyTwoInts
print("Result: \(mathFunction(2, 3))") // Prints "Result: 6"
let anotherMathFunction = addTwoInts //Type can be inferred
Pass function as parameter types
func printMathResult(_ mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) {
print("Result: \(mathFunction(a, b))")
}
printMathResult(addTwoInts, 3, 5) // Prints "Result: 8"
//Pass function as return types
func stepForward(_ input: Int) -> Int {
return input + 1
}
func stepBackward(_ input: Int) -> Int {
return input - 1
}
func chooseStepFunction(backward: Bool) -> (Int) -> Int {
return backward ? stepBackward : stepForward
}
var currentValue = 3
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
print("Counting to zero:")
//Counting to zero:
while currentValue != 0 {
print("\(currentValue)... ")
currentValue = moveNearerToZero(currentValue)
}
print("zero!")
func chooseStepFunction(backward: Bool) -> (Int) -> Int {
func stepForward(input: Int) -> Int { return input + 1 }
func stepBackward(input: Int) -> Int { return input - 1 }
return backward ? stepBackward : stepForward
}
var currentValue = -4
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
// moveNearerToZero now refers to the nested stepForward() function
while currentValue != 0 {
print("\(currentValue)... ")
currentValue = moveNearerToZero(currentValue)
}
print("zero!")
// -4...
// -3...
// -2...
// -1...
// zero!
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
func backward(_ s1: String, _ s2: String) -> Bool {
return s1 > s2
}
var reversedNames = names.sorted(by: backward) // reversedNames is equal to ["Ewa", "Daniella", "Chris", "Barry", "Alex"]
reversedNames = names.sorted(by: {(s1: String, s2: String) -> Bool in
return s1 > s2
})
reversedNames = names.sorted(by: {s1, s2 in return s1 > s2})
reversedNames = names.sorted(by: {s1, s2 in s1 > s2})
reversedNames = names.sorted(by: {$0 > $1})
reversedNames = names.sorted(by: >)
If you need to pass a closure expression to a function as the function’s final argument, it can be useful to write it as a trailing closure instead. A trailing closure is written after the function call’s parentheses, even though it is still an argument to the function.
reversedNames = names.sorted() { $0 > $1 }
reversedNames = names.sorted { $0 > $1 } //If closure is the only argument
Here’s how you can use the map(_:) method with a trailing closure to convert an array of Int values into an array of String values. The array [16, 58, 510] is used to create the new array ["OneSix", "FiveEight", "FiveOneZero"]:
let digitNames = [
0: "Zero", 1: "One", 2: "Two", 3: "Three", 4: "Four",
5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
]
let numbers = [16, 58, 510]
let closure = { (number : Int) -> String in
var number = number
var output = ""
repeat {
output = digitNames[number % 10]! + output
number /= 10
} while number > 0
return output
}
let strings = numbers.map(closure)
let strings2 = numbers.map{ (number : Int) -> String in
var number = number
var output = ""
repeat {
output = digitNames[number % 10]! + output
number /= 10
} while number > 0
return output
}
A nested function can capture any of its outer function’s arguments and can also capture any constants and variables defined within the outer function.
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementer() -> Int {
runningTotal += amount
return runningTotal
}
return incrementer
}
var incrementBy5 = makeIncrementer(forIncrement: 5)
print(incrementBy5()) // 5
print(incrementBy5()) // 10
var anotherIncrementBy5 = incrementBy5
print(anotherIncrementBy5()) // 15
var incrementBy10 = makeIncrementer(forIncrement: 10)
print (incrementBy10()) // 10
print (incrementBy10()) // 20
print (incrementBy10()) // 30
var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) { //completionHandler will be called later in the code after someFunctionWithEscapingClosure() is called
completionHandlers.append(completionHandler)
}
func someFunctionWithNonescapingClosure(closure: () -> Void) {
closure()
}
class SomeClass {
var x = 10
func doSomething() {
someFunctionWithEscapingClosure {
print ("set x to 100")
self.x = 100
}
someFunctionWithNonescapingClosure {
print ("set x to 200")
x = 200
}
}
}
let instance = SomeClass()
instance.doSomething()
print(instance.x) //200 , "set x to 100" is not printed
completionHandlers.first?()
print(instance.x) //100
var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
print(customersInLine.count) // Prints "5"
let customerProvider = { customersInLine.remove(at: 0) } //type is () -> String
print(customersInLine.count) // Prints "5"
print("Now serving \(customerProvider())!") // Prints "Now serving Chris!"
print(customersInLine.count) // Prints "4"
// customersInLine is ["Ewa", "Barry", "Daniella"]
func serve(customer customerProvider: () -> String) {
print("Now serving \(customerProvider())!")
}
serve(customer: {customersInLine.remove(at: 0)}) // Prints "Now serving Alex!"
// customersInLine is ["Ewa", "Barry", "Daniella"]
func serve(customer customerProvider: @autoclosure () -> String) {
print("Now serving \(customerProvider())!")
}
serve(customer: {customersInLine.remove(at: 0)}) // Prints "Now serving Ewa!"
serve(customer: customersInLine.remove(at: 0)) // {} can be omitted due to @autoclosure. Prints "Now serving Barry!"
enum Beverage: CaseIterable {
case coffee, tea, juice
}
let numberOfChoices = Beverage.allCases.count
print("\(numberOfChoices) beverages available")
for beverage in Beverage.allCases {
print(beverage)
}
enum Barcode {
case upc(Int, Int, Int, Int)
case qrCode(String)
}
var productBarcode = Barcode.upc(8, 85909, 51226, 3)
switch productBarcode {
case .upc(let numberSystem, let manufacturer, let product, let check):
print("UPC: \(numberSystem), \(manufacturer), \(product), \(check).")
case .qrCode(let productCode):
print("QR code: \(productCode).")
}
enum Animal: String {
case cat = "tom"
case mouse = "jerry"
case duck = "donald"
}
let aMouse = Animal.mouse
print(aMouse.rawValue)
enum Planet: Int, CaseIterable { //Implict raw values. the implicit value for each case is one more than the previous case.
case mercury = 100, venus, earth, mars, jupiter, saturn, uranus, neptune
}
for p in Planet.allCases{
print ("\(p) = \(p.rawValue)") // 100 - 108
}
let possiblePlanet = Planet(rawValue: 102) //earth
enum ArithmeticExpression {
case number(Int)
indirect case addition(ArithmeticExpression, ArithmeticExpression)
indirect case multiplication(ArithmeticExpression, ArithmeticExpression)
}
let five = ArithmeticExpression.number(5)
let four = ArithmeticExpression.number(4)
let sum = ArithmeticExpression.addition(five, four)
let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))
func evaluate(_ expression: ArithmeticExpression) -> Int {
switch expression {
case let .number(value):
return value
case let .addition(left, right):
return evaluate(left) + evaluate(right)
case let .multiplication(left, right):
return evaluate(left) * evaluate(right)
}
}
print(evaluate(product))
Structs are value types while Classes are reference types
var struct1 = MyStruct()
struct1.name = "old name"
var struct2 = struct1
struct2.name = "new name"
//Now struct1.name = "old name"
var class1 = MyClass()
class1.name = "old name"
var class2 = class1
class2.name = "new name"
//Now class1.name = "new name"
Note that identical to (represented by three equals signs, or ===) doesn’t mean the same thing as equal to (represented by two equals signs, or ==).
let class1 = MyClass(name: "name")
let class2 = class1
let class3 = MyClass(name: "name")
class1 === class2 //True
class1 === class3 //False
class1 == class3 //Maybe True TODO
class DataImporter {
var filename : String
init() {
print ("Init Data Importer")
filename = "data.txt"
}
// the DataImporter class would provide data importing functionality here
}
class DataManager {
lazy var importer = DataImporter()
//var importer = DataImporter()
func doStuff(){
print ("Do stuff")
}
func doImport(){
print (importer.filename)
}
}
let manager = DataManager()
manager.doStuff()
manager.doImport()
// Prints Do stuff, Init Data Importer, data.txt with lazy keyword
// Prints Init Data Importer, Do stuff, data.txt without lazy keyword
struct AlternativeRect {
var origin = Point()
var size = Size()
var center: Point {
get {
let centerX = origin.x + (size.width / 2)
let centerY = origin.y + (size.height / 2)
return Point(x: centerX, y: centerY)
}
set {
origin.x = newValue.x - (size.width / 2)
origin.y = newValue.y - (size.height / 2)
}
}
}
class StepCounter {
var totalSteps: Int = 0 {
willSet {
print("About to set totalSteps to \(newValue), add to \(totalSteps)")
}
didSet {
if totalSteps > oldValue {
print("Added \(totalSteps - oldValue) steps")
}
}
}
}
let stepCounter = StepCounter()
stepCounter.totalSteps = 200
// About to set totalSteps to 200
// Added 200 steps
stepCounter.totalSteps = 360
// About to set totalSteps to 360
// Added 160 steps
stepCounter.totalSteps = 896
// About to set totalSteps to 896
// Added 536 steps
struct SomeStructure {
static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int {
return 1
}
}
print(SomeStructure.storedTypeProperty) // Prints "Some value."
SomeStructure.storedTypeProperty = "Another value."
print(SomeStructure.storedTypeProperty) // Prints "Another value."
print(SomeStructure.computedTypeProperty) // Prints "1"
SomeStructure.computedTypeProperty = 6 //Compilation error as computedTypeProperty is a read only property
struct Point {
var x = 0.0, y = 0.0
mutating func moveBy(x deltaX: Double, y deltaY: Double) {
x += deltaX
y += deltaY
}
}
struct Point {
var x = 0.0, y = 0.0
mutating func moveBy(x deltaX: Double, y deltaY: Double) {
self = Point(x: x + deltaX, y: y + deltaY)
}
}
enum TriStateSwitch {
case off, low, high
mutating func next() {
switch self {
case .off:
self = .low
case .low:
self = .high
case .high:
self = .off
}
}
}
var ovenLight = TriStateSwitch.low
ovenLight.next() // ovenLight is now equal to .high
ovenLight.next() // ovenLight is now equal to .off
class SomeClass {
class func someTypeMethod1() {
print ("calling method 1")
}
static func someTypeMethod2() {
print ("calling method 2")
}
}
SomeClass.someTypeMethod1() //Prints "calling method 1"
SomeClass.someTypeMethod2() //Prints "calling method 2"
struct TimesTable {
let multiplier: Int
subscript(index: Int) -> Int {
return multiplier * index
}
}
let threeTimesTable = TimesTable(multiplier: 3)
print("six times three is \(threeTimesTable[6])")
struct Matrix {
let rows: Int, columns: Int
var grid: [Double]
init(rows: Int, columns: Int) {
self.rows = rows
self.columns = columns
grid = Array(repeating: 0.0, count: rows * columns)
}
func indexIsValid(row: Int, column: Int) -> Bool {
return row >= 0 && row < rows && column >= 0 && column < columns
}
subscript(row: Int, column: Int) -> Double {
get {
assert(indexIsValid(row: row, column: column), "Index out of range")
return grid[(row * columns) + column]
}
set {
assert(indexIsValid(row: row, column: column), "Index out of range")
grid[(row * columns) + column] = newValue
}
}
}
var matrix = Matrix(rows: 2, columns: 2)
matrix[0, 1] = 1.5
matrix[1, 0] = 3.2
print (matrix[0, 1]) //Prints 1.5
print (matrix[2, 2]) //Error: Index out of range
class Vehicle {
var currentSpeed = 0.0
var description: String {
return "traveling at \(currentSpeed) miles per hour"
}
func makeNoise() {
// do nothing - an arbitrary vehicle doesn't necessarily make a noise
}
}
class Car: Vehicle {
var gear = 1
override var description: String {
return super.description + " in gear \(gear)"
}
}
let car = Car()
car.description
class AutomaticCar: Car {
override var currentSpeed: Double {
didSet {
gear = Int(currentSpeed / 10.0) + 1
}
}
}
let automatic = AutomaticCar()
automatic.currentSpeed = 35.0
print("AutomaticCar: \(automatic.description)")
struct Celsius {
var temperatureInCelsius: Double
init(fromFahrenheit fahrenheit: Double) {
temperatureInCelsius = (fahrenheit - 32.0) / 1.8
}
init(fromKelvin kelvin: Double) {
temperatureInCelsius = kelvin - 273.15
}
}
let boilingPointOfWater = Celsius(fromFahrenheit: 212.0) // boilingPointOfWater.temperatureInCelsius is 100.0
let freezingPointOfWater = Celsius(fromKelvin: 273.15) // freezingPointOfWater.temperatureInCelsius is 0.0
struct Size {
var width = 0.0, height = 0.0
}
let twoByTwo = Size(width: 2.0, height: 2.0) //Good
class Size2 {
var width = 0.0, height = 0.0
}
let twoByTwo2 = Size2(width: 2.0, height: 2.0) //Compilation error
struct Size {
var width = 0.0, height = 0.0
}
struct Point {
var x = 0.0, y = 0.0
}
struct Rect {
var origin = Point()
var size = Size()
init() {}
init(origin: Point, size: Size) {
self.origin = origin
self.size = size
}
init(center: Point, size: Size) {
let originX = center.x - (size.width / 2)
let originY = center.y - (size.height / 2)
self.init(origin: Point(x: originX, y: originY), size: size)
}
}
class Food {
var name: String
init(name: String) { //designated init
self.name = name
}
convenience init() {
self.init(name: "[Unnamed]") //Convenience init() must call designated init()
}
}
class RecipeIngredient: Food {
var quantity: Int
init(name: String, quantity: Int) { //designated init
self.quantity = quantity
//self.name = name //This line causes compilation error
super.init(name: name)
}
override convenience init(name: String) { //Convenience init
self.init(name: name, quantity: 1)
}
convenience init(quantity: Int) {
self.init(name:"[Unnamed]", quantity: quantity)
}
}
let oneMysteryItem = RecipeIngredient() //no-arg init() is inherited from superclass
let oneBacon = RecipeIngredient(name: "Bacon")
let sixEggs = RecipeIngredient(name: "Eggs", quantity: 6)
class ShoppingListItem: RecipeIngredient {
var purchased = false
var price = 0.0
var description: String {
var output = "\(quantity) x \(name)"
output += purchased ? " ✔" : " ✘"
return output
}
}
//Because it provides a default value for all of the properties it introduces and does not define any initializers itself, ShoppingListItem automatically inherits all of the designated and convenience initializers from its superclass.
let shoppingList1 = ShoppingListItem()
let shoppingList2 = ShoppingListItem(name: "banana", quantity: 2)
let shoppingList3 = ShoppingListItem(name: "banana")
let shoppingList4 = ShoppingListItem(quantity: 3)
struct Animal {
let species: String
init?(species: String) {
if species.isEmpty { return nil }
self.species = species
}
}
Enumerations with raw values automatically receive a failable initializer, init?(rawValue:)
enum TemperatureUnit: Character {
case kelvin = "K", celsius = "C", fahrenheit = "F"
}
let fahrenheitUnit = TemperatureUnit(rawValue: "F")
if fahrenheitUnit != nil {
print("This is a defined temperature unit, so initialization succeeded.")
}
let unknownUnit = TemperatureUnit(rawValue: "X")
if unknownUnit == nil {
print("This is not a defined temperature unit, so initialization failed.")
}
class Document {
var name: String?
// this initializer creates a document with a nil name value
init() {}
// this initializer creates a document with a nonempty name value
init?(name: String) {
if name.isEmpty { return nil }
self.name = name
}
}
class UntitledDocument: Document {
override init() {
super.init(name: "[Untitled]")!
}
}
Write the required modifier before the definition of a class initializer to indicate that every subclass of the class must implement that initializer
class SomeClass {
required init() {
// initializer implementation goes here
}
}
class SomeSubclass: SomeClass {
required init() {
// subclass implementation of the required initializer goes here
}
}
class SomeClass {
let someProperty: SomeType = {
// create a default value for someProperty inside this closure
// someValue must be of the same type as SomeType
return someValue
}()
}
Note that the closure’s end curly brace is followed by an empty pair of parentheses. This tells Swift to execute the closure immediately. If you omit these parentheses, you are trying to assign the closure itself to the property, and not the return value of the closure.
class Bank {
static var coinsInBank = 10_000
static func distribute(coins numberOfCoinsRequested: Int) -> Int {
let numberOfCoinsToVend = min(numberOfCoinsRequested, coinsInBank)
coinsInBank -= numberOfCoinsToVend
return numberOfCoinsToVend
}
static func receive(coins: Int) {
coinsInBank += coins
}
}
class Player {
var coinsInPurse: Int
var name: String
init(name: String, coins: Int) {
self.name = name
coinsInPurse = Bank.distribute(coins: coins)
}
func win(coins: Int) {
coinsInPurse += Bank.distribute(coins: coins)
}
deinit {
print("Player \(name) has left the game")
Bank.receive(coins: coinsInPurse)
}
}
var playerOne: Player? = Player(name: "Josh", coins: 100)
print("A new player has joined the game with \(playerOne!.coinsInPurse) coins")
// Prints "A new player has joined the game with 100 coins"
print("There are now \(Bank.coinsInBank) coins left in the bank")
// Prints "There are now 9900 coins left in the bank"
playerOne!.win(coins: 2_000)
print("PlayerOne won 2000 coins & now has \(playerOne!.coinsInPurse) coins")
// Prints "PlayerOne won 2000 coins & now has 2100 coins"
print("The bank now only has \(Bank.coinsInBank) coins left")
// Prints "The bank now only has 7900 coins left"
playerOne = nil
// Prints "Player Josh has left the game"
print("The bank now has \(Bank.coinsInBank) coins")
// Prints "The bank now has 10000 coins"