21 - iOS Swift
Swift
-
Started in July 2010 – Chris Lattner
-
1.0 Sept 9, 2014
-
2.0 WWDC 2015
-
2.2 Open Source (swift.org) Dec 3, 2015
-
3.0 Sept 13, 2016
-
4.0 Sept 19 2017, 4.1 March 2018, 4.2 Sept 2018
-
5.0 March 3 2019
-
2015 – Most loved programming language – first place (Stack Overflow)
-
2016 – Second place
-
2017-2018 In top 5
Swift Playgrounds
- iPad app, 3D video game-like interface, moving closer to full editor
- Xcode
- Web based - http://online.swiftplayground.run
Swift variables
Constants
let school: String = "TalTech IT College"
let founded: Int = 2000
let isAwesome: Bool = true
Type inference
let school = "TalTech IT College"
let founded = 2000
let isAwesome = true
Variables
var age = 16
Strings
Concatenation
let school = "TalTech IT College"
let message = "Hello, " + school + "!"
Interpolation
let school = "TalTech IT College"
let message = "Hello, \(school)!"
Full unicode support
let õäöüžšج信息技术 = "信息技术õäüöžšب ت جث"
Characters
let õäöüžšج信息技术 = "信息技术õäüöžšب ت جث"
print("\(õäöüžšج信息技术) is \(õäöüžšج信息技术.count) chars long")
\\ 16
Iteration
let õäöüžšج信息技术 = "信息技术õäüöžšب ت جث"
for character in õäöüžšج信息技术 {
print(character)
}
Collections
Array and Dictionary
let names: [String] = ["Jüri", "Mari", "Kalle"]
let ages = ["Kalle": 17, "Malle": 18]
Loops
While and Repeat-While
var name = "test"
var i = 0
while i < name.characters.count {
print("At pos \(i) is \(name[name.index(name.startIndex, offsetBy: i)])")
i += 1
}
i = 0
repeat {
print("At pos \(i) is \(name[name.index(name.startIndex, offsetBy: i)])")
i += 1
} while i < name.characters.count
For-In Loop – closed ranges
for number in 1...5 {
print(number)
}
Half closed ranges
let numbers = [7, 6, 42, 3, 9, 1]
let maxCount = 4
for index in 0..<maxCount {
print(numbers[index])
}
For-In Loop – Array & Dictionary
let ages = ["Kalle": 17, "Malle": 18]
for (name, age) in ages {
print("\(name) - \(age)")
}
Array
Modifying
var numbers = [7, 6, 42, 3, 9, 1]
numbers.append(5)
numbers[1] = 8
Append multiple
numbers.append(contentsOf: [4, 13, -5])
Remove elements (0 based index) and insert new ones
numbers[3...5] = [1, 2]
Optionals
Maybe value is not there?
let ages = ["Kalle": 17, "Malle": 18]
let possibleAge = ages["Malle"]
print("\(possibleAge)")
let possibleAge: Int? = ages["Malle"]
Checking
if possibleAge == nil {
print("Age not found.")
}
if let
let ages = ["Kalle": 17, "Malle": 18]
if let age = ages["Kalle"] {
print("Kalle's age is \(age)")
}
switch
let age = 90
switch age {
case 1:
print("First year done")
case 13...19:
print("Teenager is hard period!")
case let decade where decade % 10 == 0:
print("Congrats on \(decade)*10 years")
default:
print("regular birthday")
Switch over multiple values
let userName = "admin"
let passwordIsValid = true
switch (userName, passwordIsValid) {
case ("admin", true):
print("admin you are")
case ("guest", _):
print("guests not allowed")
case (_, let isValid):
print(isValid ? "admin area granted" : "DENIED")
}
Functions
func sendMessage() {
let message = "Hello!"
print(message)
}
sendMessage()
Parameters
func sendMessage(shouting: Bool) {
var message = "Hello!"
message = shouting ? message.uppercased() : message
print(message)
}
sendMessage(shouting: true)
Multiple parameters (argument, label)
func sendMessage(recipient: String, shouting: Bool) {
let message = "Hello \(recipient)!"
print(shouting ? message.uppercased() : message)
}
sendMessage(recipient: "Andres", shouting: true)
Better to read in usage, bad in function code
func sendMessage(to: String, shouting: Bool) {
let message = "Hello \(to)!"
print(shouting ? message.uppercased() : message)
}
sendMessage(to: "Andres", shouting: true)
Parameters - argument label and a parameter name
func sendMessage(to recipient: String, shouting: Bool) {
let message = "Tere \(recipient)!"
print(shouting ? message.uppercased() : message)
}
sendMessage(to: "Andres", shouting: true)
Parameters – using underscore – no label
func sendMessage(message: String, to recipient: String, shouting: Bool) {
let message = "\(message), \(recipient)!"
print(shouting ? message.uppercased() : message)
}
sendMessage(message: "Hello", to: "Andres", shouting: true)
func sendMessage(_ message: String, to recipient: String, shouting: Bool) {
let message = "\(message), \(recipient)!"
print(shouting ? message.uppercased() : message)
}
sendMessage("Hello", to: "Andres", shouting: true)
Return values
func firstString(havingPrefix prefix: String, in strings: [String]) -> String? {
for string in strings {
if string.hasPrefix(prefix){
return string
}
}
return nil
}
print("Result \(firstString(havingPrefix: "And", in: ["Jüri", "Andres"]))")
Function type
Function type
(parameter types) -> return type
func sendMessage() {}
() -> Void
func firstStr(havingPrefix prefix: String, in strings: [String]) -> String? {}
(String, [String]) -> String?
Functions as parameters
func filterInts(_ numbers: [Int], _ includeNumber: (Int) -> Bool) -> [Int] {
var result: [Int] = []
for number in numbers {
if includeNumber(number) {
result.append(number)
}
}
return result
}
let numbers = [4, 17, 34, 41]
func divisibleByTwo(_ number: Int) -> Bool {
return number % 2 == 0
}
let evenNumbers = filterInts(numbers, divisibleByTwo)
print(evenNumbers)
Closure expression - Inline function definitions (not named functions)
func divisibleByTwo(_ number: Int) -> Bool {
return number % 2 == 0
}
let evenNumbers =
filterInts(numbers, { (number: Int) -> Bool in return number % 2 == 0})
Closures - definition
func filterInts(_ numbers: [Int], _ includeNumber: (Int) -> Bool) -> [Int] {……}
let numbers = [4, 17, 34, 41]
print( filterInts(numbers, { (number: Int) -> Bool in return number % 2 == 0}) )
// can be inferred from filterIntents declaration
print( filterInts(numbers, { number in return number % 2 == 0}) )
// if its single liner, no need for return keyword
print( filterInts(numbers, { number in number % 2 == 0}) )
// implicit arguments, no need for in keyword
print( filterInts(numbers, {$0 % 2 == 0}) )
// if closure is last argument, you can write as trailing closure
print( filterInts(numbers) {$0 % 2 == 0} )
Generics
let numbers = [4, 17, 34, 41]
let names = ["Andres", "kala"]
func filter<TElement>(_ source: [TElement],
_ includeElement: (TElement) -> Bool) -> [TElement] {
var result: [TElement] = []
for elem in source {
if includeElement(elem) {
result.append(elem)
}
}
return result
}
let evenNumbers = filter(numbers) { $0 % 2 == 0 }
let shortNames = filter(names) { name in name.count < 5 }
Map, Filter
Closures and generics are widely used in Swift libraries
let names = ["Lily", "Santiago", "Aadya", "Jack", "Anna", "Andrés"]
let shortNames = names.filter({ name in name.count < 5 })
let shortNames1 = names.filter() { name in name.count < 5 }
let shortNames2 = names.filter { name in name.count < 5 }
print(shortNames)
let capitalizedShortNames = shortNames.map { name in name.uppercased() }
print(capitalizedShortNames)