Welcome to FutureAppLaboratory

v=(*^ワ^*)=v

Learning Swift Part 1 - a Swift Tour

| Comments

Just some notes after reading Apple’s official online guide. Most code are from the guide, with some modification by me.

Modified some code in the following parts. Some better example or fixing in new Xcode.

  • Function as parameter (like Comparator)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Bubble sort with a custom comparator
func sort(inout list: [Int], sorter: ((Int, Int) -> Bool)) {
    var i : Int = 0
    while i < list.count {
        var j : Int = i + 1
        if j < list.count && !sorter(list[i], list[j]) {
            var temp = list[i]
            list[i] = list[j]
            list[j] = temp
        }
        i++
    }
}
var list = [3, 2, 1]
func sorter(a : Int, b : Int) -> Bool {
    return a < b
}
sort(&list, sorter)
  • Closure
1
2
3
4
5
6
7
8
9
10
11
numbers.map({
    (number: Int) -> Int in
    let result = 3 * number
    return result
})
// can be simplied to
numbers.map({ number in 3 * number })
// sort a array
var list = [3, 2, 1]
sort(&list) // NOT sort(list), this function only accept a reference
var listSorted = sorted(list) // This is OK

===== Full Notes =====

A Swift Tour

  • variable.
1
2
3
    var myVariable = 42   // variable
    myVariable = 50       // variable
    let myConstant = 42   // Constant
  • implicit vs explicit.
1
2
3
    let implicitInteger = 70
    let implicitDouble = 70.0
    let explicitDouble: Double = 70  // Type is written right to variable
  • Values never implicitly converted.
1
2
3
    let label = "The width is"
    let width = 94
    let withlabel = label + String(width)
  • Include values in strings.
1
2
3
4
    let apples = 3
    let oranges = 5
    let appleSummary = "I have \(apples) apples."
    let fruitSummary = "I have \(apples + oranges) pieces of fruit."
  • Arrays and Dictionaries.
1
2
3
4
5
6
7
8
    var shopppingList = ["catfish", "water", "tulips", "blue paint"] // [] for empty array
    shoppingList[1] = "bottle of water"

    var occupations = [
        "Malcolm": "Captain",
        "Kaylee": "Mechanic",
    ] // [:] for empty dictionary
    occupations["Jayne"] = "Public Relations"

Control Flows

  • for-in
1
2
3
4
5
6
7
8
9
10
    let individualScores = [75, 43, 103, 87, 12]
    var teamScore = 0
    for score in individualScores {
        if score > 50 {
            teamScore += 3
        } else {
            teamScore += 1
        }
    }
    teamScore
  • optional-value with if
1
2
3
4
5
6
7
8
    var optionalString: String? = "Hello"
    optionalString == nil

    var optionalName: String? = "John Appleseed"
    var greeting = "Hello!"
    if let name = optionalName {
        greeting = "Hello, \(name)"
    }
  • switch
1
2
3
4
5
6
7
8
9
10
11
    let vegetable = "red pepper"
    switch vegetable {
        case "celery":
            let vegetableComment = "Add some raisins and make ants on a log."
        case "cucumber", "watercress":
            let vegetableComment = "That would make a good tea sandwich."
        case let x where x.hasSuffix("pepper"):
            let vegetableComment = "Is it a spicy \(x)?"
        default:
            let vegetableComment = "Everything tastes good in soup."
    }
  • for-in in dictionary
1
2
3
4
5
6
7
8
9
10
11
12
13
14
    let interestingNumbers = [
        "Prime": [2, 3, 5, 7, 11, 13],
        "Fibonacci": [1, 1, 2, 3, 5, 8],
        "Square": [1, 4, 9, 16, 25],
    ]
    var largest = 0
    for (kind, numbers) in interestingNumbers {
        for number in numbers {
            if number > largest {
                largest = number
            }
        }
    }
    largest
  • while and do-while
1
2
3
4
5
6
7
8
9
10
11
    var n = 2
    while n < 100 {
        n = n * 2
    }
    n

    var m = 2
    do {
        m = m * 2
    } while m < 100
    m
  • range operators
1
2
3
4
5
6
7
    for i in 0..<3 {
        // do something, for 0, 1, 2
    }

    for i in 0...3 {
        // do something, for 0, 1, 2, 3
    }

Functions and Closures

  • A classic one
1
2
3
4
    func greet(name: String, day: String) -> String {
        return "Hello \(name), today is \(day)."
    }
    greet("Bob", "Tuesday")
  • Use a tuple as return value
1
2
3
4
    func getGasPrices() -> (Double, Double, Double) {
        return (3.59, 3.69, 3.79)
    }
    getGasPrices()
  • Variable Arguments (varargs)
1
2
3
4
5
6
7
8
9
    func sumOf(numbers: Int...) -> Int {
        var sum = 0
        for number in numbers {
                sum += number
            }
        return sum
    }
    sumOf()
    sumOf(42, 597, 12)
  • Nested functions
1
2
3
4
5
6
7
8
9
    func returnFifteen() -> Int { // Wrapper function
        var y = 10
        func add() { // Nested function
            y += 5
        }
        add()
        return y
    }
    returnFifteen()
  • Function as return value (like pointer of function)
1
2
3
4
5
6
7
8
    func makeIncrementer() -> (Int -> Int) {
        func addOne(number: Int) -> Int {
                return 1 + number
            }
        return addOne
    }
    var increment = makeIncrementer()
    increment(7)
  • Function as parameter (like Comparator)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    // Bubble sort with a custom comparator
    func sort(inout list: [Int], sorter: ((Int, Int) -> Bool)) {
        var i : Int = 0
        while i < list.count {
            var j : Int = i + 1
            if j < list.count && !sorter(list[i], list[j]) {
                var temp = list[i]
                list[i] = list[j]
                list[j] = temp
            }
            i++
        }
    }
    var list = [3, 2, 1]
    func sorter(a : Int, b : Int) -> Bool {
        return a < b
    }
    sort(&list, sorter)
  • Closure
1
2
3
4
5
6
7
8
9
10
11
    numbers.map({
        (number: Int) -> Int in
        let result = 3 * number
        return result
    })
    // can be simplied to
    numbers.map({ number in 3 * number })
    // sort a array
    var list = [3, 2, 1]
    sort(&list) // NOT sort(list), this function only accept a reference
    var listSorted = sorted(list) // This is OK

Objects and Classes

  • A simple class
1
2
3
4
5
6
7
8
9
10
    class Shape {
        var numberOfSides = 0
        func simpleDescription() -> String {
                return "A shape with \(numberOfSides) sides."
            }
    }

    var shape = Shape()
    shape.numberOfSides = 7
    var shapeDescription = shape.simpleDescription()
  • Initializer and its opposite
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    class NamedShape {
        var numberOfSides: Int = 0
        var name: String

        init(name: String) {
            self.name = name
        }

        deinit {

        }

        func simpleDescription() -> String {
            return "A shape with \(numberOfSides) sides."
        }
    }
  • Subclass
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    class Square: NamedShape {
        var sideLength: Double

        init(sideLength: Double, name: String) {
            self.sideLength = sideLength
            super.init(name: name)
            numberOfSides = 4
        }

        func area() -> Double {
            return sideLength * sideLength
        }

        override func simpleDescription() -> String {
            return "A square with sides of length \(sideLength)."
        }
    }
    let test = Square(sideLength: 5.2, name: "my test square")
    test.area()
    test.simpleDescription()
  • Setter and Getter on properties
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
    class EquilateralTriangle: NamedShape {
        var sideLength: Double = 0.0

        init(sideLength: Double, name: String) {
            self.sideLength = sideLength
            super.init(name: name)
            numberOfSides = 3
        }

        var perimeter: Double {
        get {
                return 3.0 * sideLength
            }
        set {
                sideLength = newValue / 3.0
            }
        }

        override func simpleDescription() -> String {
            return "An equilateral triagle with sides of length \(sideLength)."
        }
    }
    var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")
    triangle.perimeter
    triangle.perimeter = 9.9
    triangle.sideLength
  • Provide code after before or after setting properties
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
    class TriangleAndSquare {
        var triangle: EquilateralTriangle {
            willSet {                                    // Do something after before setting properties
                square.sideLength = newValue.sideLength
            }
        }
        var square: Square {
            willSet {                                    // Do something after before setting properties
                triangle.sideLength = newValue.sideLength
            }
        }
        init(size: Double, name: String) {
            square = Square(sideLength: size, name: name)
            triangle = EquilateralTriangle(sideLength: size, name: name)
        }
    }
    var triangleAndSquare = TriangleAndSquare(size: 10, name: "another test shape")
    triangleAndSquare.square.sideLength
    triangleAndSquare.triangle.sideLength
    triangleAndSquare.square = Square(sideLength: 50, name: "larger square")
    triangleAndSquare.triangle.sideLength

Enumerations and Structures

  • Enumerations can have methods
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
    enum Rank: Int {
        case Ace = 1
        case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
        case Jack, Queen, King
        func simpleDescription() -> String {
            switch self {
            case .Ace:
                return "ace"
            case .Jack:
                return "jack"
            case .Queen:
                return "queen"
            case .King:
                return "king"
            default:
                return String(self.toRaw())
            }
        }
    }
    let ace = Rank.Ace
    let aceRawValue = ace.toRaw()
  • Convert enum between raw values
1
2
3
4
5
6
7
    let ace = Rank.Ace
    let aceRawValue = ace.toRaw()
    let aceString = ace.simpleDescription()

    if let convertedRank = Rank.fromRaw(3) {
        let threeDescription = convertedRank.simpleDescription()
    }
  • Structure is similar to Class, but when structures are always copied when they are passed around, while classes are passed by reference.
1
2
3
4
5
6
7
8
9
    struct Card {
        var rank: Rank
        var suit: Suit
        func simpleDescription() -> String {
            return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
        }
    }
    let threeOfSpades = Card(rank: .Three, suit: .Spades)
    let threeOfSpadesDescription = threeOfSpades.simpleDescription()
  • Structure with associated values.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
    enum ServerResponse {
        case Result(String, String)
        case Error(String)
    }

    let success = ServerResponse.Result("6:00 am", "8:09 pm")
    let failure = ServerResponse.Error("Out of cheese.")

    switch success {
    case let .Result(sunrise, sunset):
        let serverResponse = "Sunrise is at \(sunrise) and sunset is at \(sunset)."
    case let .Error(error):
        let serverResponse = "Failure...  \(error)"
    }

Protocols and Extendsions

  • A classic Protocol.
1
2
3
4
    protocol ExampleProtocol {
        var simpleDescription: String { get }
        mutating func adjust()  // "mutating" is needed when a protocol need to modify a structure
    }
  • Classes, enumerations and structures can all adopt protocols.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    class SimpleClass: ExampleProtocol {
        var simpleDescription: String = "A very simple class."
        var anotherProperty: Int = 69105
        func adjust() {
            simpleDescription += "  Now 100% adjusted."
        }
    }
    var a = SimpleClass()
    a.adjust()
    let aDescription = a.simpleDescription

    struct SimpleStructure: ExampleProtocol {
        var simpleDescription: String = "A simple structure"
        mutating func adjust() {
            simpleDescription += " (adjusted)"
        }
    }
    var b = SimpleStructure()
    b.adjust()
    let bDescription = b.simpleDescription
  • Extension to add functionality to an existing type.
1
2
3
4
5
6
7
8
9
    extension Int: ExampleProtocol {
        var simpleDescription: String {
        return "The number \(self)"
        }
        mutating func adjust() {
            self += 42
        }
    }
    7.simpleDescription
  • Use Protocol as a variable. (Abstracting)
1
2
3
    let protocolValue: ExampleProtocol = a
    protocolValue.simpleDescription
    // protocolValue.anotherProperty  // Even this is an instance of 'SimpleClass', we cannot access its member not defined in 'ExampleProtocol'

Generics

  • A classic generic sample.
1
2
3
4
5
6
7
8
9
    func repeat<ItemType>(item: ItemType, times: Int) -> [ItemType] {
        var result = [ItemType]()
        for i in 0..<times {
            result += [item]   // operator += , which are used against Array operands need to be wrapped in []
                               // means that expand the list by one element
        }
        return result
    }
    repeat("knock", 4)
  • Generic can also be used on functions and methods, as well as classes, enumerations, and structures.
1
2
3
4
5
6
7
    // Reimplement the Swift standard library's optional type
    enum OptionalValue<T> {
        case None
        case Some(T)
    }
    var possibleInteger: OptionalValue<Int> = .None
    possibleInteger = .Some(100)
  • Add requirements in Generic
1
2
3
4
5
6
7
8
9
10
11
    func anyCommonElements <T, U where T: SequenceType, U: SequenceType, T.Generator.Element: Equatable, T.Generator.Element == U.Generator.Element> (lhs: T, rhs: U) -> Bool {
        for lhsItem in lhs {
            for rhsItem in rhs {
                if lhsItem == rhsItem {
                    return true
                }
            }
        }
        return false
    }
    anyCommonElements([1, 2, 3], [3])

Comments