Ilya Loshkarev loshkarev.i@gmail.com
SFEDU 2016
let pi = 3.14
var r = 1.0
while r < 100 {
let sqr = r * r * pi
print("Radius: \(r); Square: \(sqr)")
r += 1
}
let
decalres a constant
var
declares a variable
Always declare a constant unless absolutely necessary
let i: Int = 1 // default Int is either Int32 or Int64
let f: Float = 2.7
let d: Double = 3.1
let b: Bool = true
let s: String = "hello"
Swift can infer type of a variable
let x = 5, y = 3.142, z = true
let names = ["Alex", "Anna", "Ivan", "Maria"]
Swift is type-safe language
var pi = 3 + 0.14 // literals don't have explicit type
let three = 3
let pointOneFour = 0.14
pi = Double(three) + pointOneFour
// implicit type conversions are not allowed
let roundPi:Int = Int(pi)
All type conversions must be explicit
func greet(person: String, from hometown: String) -> String {
return "Hello, \(person)! Glad you could visit from \(hometown)!"
}
print(greet(person: "Ivan", from: "Rostov"))
Every parameter has a name and an argument label
Arguments must be labeled when function is called
let someNum = "3.14"
let number = Double(someNum) // Double?
if number != nil {
print("parsed number: \(number!)") // unwraped value is 3.14
}
Optional value contains either value or nil
Always make sure optional contains a value before foced unwraping
let someChar: Character = "z"
if someChar >= "0" && someChar <= "9" {
print("This is a digit.")
} else if someChar >= "a" && someChar <= "z" {
print("This is a letter.")
}
Curved braces are required
let someNum = "3.14"
if let number = Double(someNum) { // number is Double!
print("parsed number: \(number)")
} else {
print("\(someNum) is not a number") // number is not reachable
}
Bound optional always contains a value
let someChar: Character = "z"
switch (someChar) {
case "a":
print("It is the first letter of the alphabet")
case "b"..."y":
print("It is some other letter of the alphabet")
case "z":
print("It is the last letter of the alphabet")
default:
print("It is some other character")
}
Case must always have a body
var i = 0
while i < 5 {
i += 1
}
repeat {
i -= 1
} while i > 0
for i in 0...10 {
for j in 0...i {
print(".")
}
print("\n")
}
func greet(person name: String, from hometown: String) -> String {
return "Hello, \(name)! Glad you could visit from \(hometown)!"
}
print(greet(person: "Ivan", from: "Rostov"))
You can ommit a label by using _
func greet(_ name: String, _ hometown: String) -> String {
return "Hello, \(name)! Glad you could visit from \(hometown)!"
}
print(greet("Ivan", "Rostov"))
Labels allow function to be called in an expressive manner
Think hard before you ommit an argument label
func swapTwo(_ a: inout Int, _ b: inout Int){
let c = a; a = b; b = c
}
var a = 1, b = 2
swapTwo(&a, &b)
All parameters are constant by default
Swift doesn't encourage functions with side effect
func add(_ a: Int, _ b: Int) -> Int {
return a + b;
}
func mult(_ a: Int, _ b: Int) -> Int {
return a * b;
}
func calc (_ op: (Int, Int) -> Int, _ a: Int, _ b: Int)) {
print(op(a, b))
}
let a = 5, b = 6
calc(add, a, b)
calc(mult, a, b)
Function's type consists of
types of parameters and return value
func +(_ left: Bool, _ right: Bool) {
return left || right
}
let a = true, b = false
let c = a + b
func counter(forward: Bool) -> (Int) -> Int {
func stepForward(input: Int) -> Int {
return input + 1
}
func stepBackward(input: Int) -> Int {
return input - 1
}
return forward ? stepForward : stepBackward
}
func counter(increment: Int, forward: Bool) -> (Int) -> Int {
func backward(input: Int) -> Int {
return input - increment
}
return !forward ? backward :
{ (input: Int) -> Int in return input + increment }
}
Closures are blocks of code that can capture
local constants and variables
// global function
func counter(increment: Int, forward: Bool) -> (Int) -> Int {
// local function – increment is captured
func backward(input: Int) -> Int {
return input - increment
}
return !forward ? backward :
// closure expression – increment is captured
{ (input: Int) -> Int in return input + increment }
}
Local functions and closure expressions
can capture any value in context
Global functions don't capture any values
let names = ["Anna", "Ivan", "Maria", "John"]
var reversedNames = names.sorted(by: {
(s1: String, s2: String) -> Bool in
return s1 > s2
})
Closure expression – unnamed block of executable code
that can capture values from local context
var reversedNames = names.sorted(by:
{ s1, s2 in return s1 > s2 })
Parameter types can be inferred from context
var reversedNames = names.sorted(by: { return $0 > $1 })
Parameters can be referenced by shorthand names
var reversedNames = names.sorted(by: { $0 > $1 })
Single-expression closure implicitly returns its result
var reversedNames = names.sorted { $0 > $1 }
Closure can be passed with trailing syntax
var reversedNames = names.sorted(by: >)
Any operator is a closure
func counter(withIncrement: Int) -> () -> Int {
var totalCount = 0
return { totalCount += withIncrement }
}
let newCounter = counter(withIncrement: 10)
print(newCounter()) // 10
let anotherCounter = newCounter
print(anotherCounter()) // 20
Closures are reference type
var names = ["Anna", "Ivan", "Maria", "John"]
let nextInLine = { names.remove(at:0) }
print("Next one is \(nextInLine()!") // Anna!
print(names.count) // 3
func whosNext(provider nextInLine: @autoclosure () -> String) {
print("Next one is \(nextInLine())")
}
whosNext(provider: names.remove(at:0))
@autoclosure
automaticaly wraps parameter
in closure expression
struct Point {
var x = 0.0, y = 0.0
}
class Polygon {
let points: [Point]
init (_ points: [Point]) {
self.points = points
}
var center: Point {
/* Calculate center */
return Point(x: xVal, y:yVal)
}
}
Classes are reference type
Structures are value type and can not be inherited
class Polygon {
let points: [Point] // has to be set in initializer
let name = "polygon" // has a default value
var area: Double { // read-only property
/* Calculate area */
}
var origin: Point {
get {/* do something */}
set(newOrigin) {/* do something */}
}
}
struct Point {
mutating func offset(_ xStep: Double, _ yStep: Double) {
/* Change x, y */
}
func distance(_ to: Point) -> Double {
/* Calculate distance */
}
}
class Polygon {
func contains(_ p: Point) -> Bool {
/* do something */
}
}
Structure methods that change properties has to be marked mutating
class Shady { // implicitly internal
private var things: [String] = []
private func stuff() {}
func allClear() {} // implicitly internal
public var totallyClear: String
}
private class Classified { // explicitly private
var nothing: String // implicitly private
}
All classes and class members are implicitly internal
class ARCout {
init(){
print ("initialized")
}
deinit() {
print ("deinitialized")
}
}
var reference1: ARCout? = ARCout() // initialized
var reference2 = reference1
reference1 = nil
reference2 = nil // deinitialized
Deallocates memory if no references to object exists
class ARCout {
var reference: ARCout?
}
var obj1 = ARCout() // initialized
var obj2 = ARCout() // initialized
obj1.reference = obj2
obj2.reference = obj1
obj1 = nil
obj2 = nil
// But nothing happened!
class ARCout {
weak var reference: ARCout?
}
weak
references don't increase retain count
unowned
references don't have to be optional values
class Triangle: Polygon {
init(_ a: Point, _ b: Point, _ c: Point) {
let verts = [a,b,c]
super.init(verts)
name = "triangle"
}
override var area: Double {
/* Calculate area */
}
func inradius: Double {
/* Calculate incircle radius */
}
}
super
provides access to superclass members
Any overwritten member should be marked with override
let shapes = [Polygon]()
/* appended something to shapes */
for shape in shapes {
if shape is Triangle {
print("it's a triangle")
}
}
for shape in shapes {
if let tri = shape as? Triangle {
print(tri.inradius)
}
}
as?
wraps result into optional,
returns nil
if variable cannot be downcasted
as!
triggers a runtime error instead
enum MyErrors: ErrorType {
case OutOfOptions
}
func chooseOption() throws -> Int {
throw MyErrors.OutOfOptions
}
ErrorType
– empty protocol for declaring errors
Only throwing functions can throw and propagate errors
do {
var option = try chooseOption()
}
catch MyErrors.OutOfOptions {
print("I'm all out of options here!")
}
try
can only be used in do-catch
block
do-catch
block stops error propagation
if it catches an error
var option = try? chooseOption() // Int?
func makeAnOption() -> Int {
var option = try! chooseOption() // just do it
return option
}
try?
wraps value into an optinal, retruns nil
if error occurs
try!
fails here and now, stops error popagation
guard let option = try? chooseOption() else {
print("Sorry, we're out of options!")
return
}
print("Congratulations, your option is \(option)")
guard
is assert-like operator that allow quick escape
if condition is not met
guard-bound optional is accesible outside of it's else clause