2015年12月19日 星期六

Node.js筆記:Raspberry Pi 安裝Node.js

Node.js

要在 Raspberry Pi 中安裝 Node.js,我是利用官方網站上下載原始碼來編譯並安裝.
執行步驟如下

$ wget https://nodejs.org/dist/v5.3.0/node-v5.3.0-linux-armv6l.tar.gz 
$ tar -xvf node-v5.3.0-linux-armv6l.tar.gz 
$ cd node-v5.3.0-linux-armv6l.tar.gz

and the last step is Copy to /usr/local.

sudo cp -R * /usr/local/

To check Node.js is properly install and you have the right version, run the command node -v.

參考:
1. http://blog.gtwang.org/iot/raspberry-pi-install-node-js-and-mongodb-database/
2. http://blog.wia.io/installing-node-js-v4-0-0-on-a-raspberry-pi/

2015年12月16日 星期三

iOS筆記:Swift(3)

Closures

Swift 中的Closures與C 和Objective-C 中的代碼塊(blocks)以及其他一些編程語言中的匿名函數比較相似。

Swift’s closure expressions have a clean, clear style, with optimizations that encourage brief, clutter-free syntax in common scenarios. These optimizations include:

  • Inferring parameter and return value types from context
  • Implicit returns from single-expression closures
  • Shorthand argument names
  • Trailing closure syntax

Closure Expressions

利用簡潔語法構建內聯閉包的方式。

The Sort Method:
Swift 標準庫提供了名為sort的方法,會根據您提供的用於排序的閉包函數將已知類型數組中的值進行排序。一旦排序完成,sort(_:)方法會返回一個與原數組大小相同,包含同類型元素且元素已正確排序的新數組。原數組不會被sort(_:)方法修改。

ex. 使用sort(_:)方法對一個String類型的數組進行字母逆序排序.
The sorting closure needs to return true if the first value should appear before the second value, and false otherwise.

        let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]

    func backwards(s1: String, _ s2: String) -> Bool {
        return s1 > s2
    }
    var reversed = names.sort(backwards)
    // reversed is equal to ["Ewa", "Daniella", "Chris", "Barry", "Alex"]

Closure Expression Syntax

Closure expression syntax has the following general form:

    { (parameters) -> return type in
        statements
    }

Closure expression syntax可以使用常量、變量和inout類型作為參數,不能提供默認值。也可以在參數列表的最後使用可變參數。Tuples也可以作為參數和返回值。

The example below shows a closure expression version of the backwards(_:_:) function from earlier:

    reversed = names.sort({ (s1: String, s2: String) -> Bool in
        return s1 > s2
    })

The start of the closure’s body is introduced by the in keyword. This keyword indicates that the definition of the closure’s parameters and return type has finished, and the body of the closure is about to begin.

上述範例也可以修改成如下形式

        reversed = names.sort( { (s1: String, s2: String) -> Bool in return s1 > s2 } )

Operator Functions

There’s actually an even shorter way to write the closure expression above.
Swift 的String類型定義了關於大於(>)的字符串實現,其作為一個函數接受兩個String類型的參數並返回Bool類型的值。而這正好與sort(_:)方法的類型一樣,所以可以改寫成如下的表達方式。

        reversed = names.sort(>)

Trailing Closures

    func someFunctionThatTakesAClosure(closure: () -> Void) {
        // function body goes here
    }

    // here's how you call this function without using a trailing closure:   
    someFunctionThatTakesAClosure({
        // closure's body goes here
    })

    // here's how you call this function with a trailing closure instead: 
    someFunctionThatTakesAClosure() {
        // trailing closure's body goes here
    }

Here’s how you can use themap(_:) method with a trailing closure to convert an array of Int values into an array of String values.

    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]

如上創建了一個數字和他們英文版本名字相映射的字典。同時還定義了一個準備轉換為字符串數組的整數數組。

You can now use the numbers array to create an array of String values, by passing a closure expression to the array’s map(_:)method as a trailing closure:

    let strings = numbers.map {
        (var number) -> String in
        var output = ""
        while number > 0 {
            output = digitNames[number % 10]! + output
            number /= 10
        }
        return output
    }
    // strings is inferred to be of type [String]
    // its value is ["OneSix", "FiveEight", "FiveOneZero"]

The call to the digitNames dictionary’s subscript is followed by an exclamation mark (!), because dictionary subscripts return an optional value to indicate that the dictionary lookup can fail if the key does not exist. In the example above, it is guaranteed that number % 10 will always be a valid subscript key for the digitNames dictionary, and so an exclamation mark is used to force-unwrap the String value stored in the subscript’s optional return value.

Capturing Values

A closure can capture constants and variables from the surrounding context in which it is defined. The closure can then refer to and modify the values of those constants and variables from within its body, even if the original scope that defined the constants and variables no longer exists.

In Swift, the simplest form of a closure that can capture values is a nested function.
ex.

    func makeIncrementer(forIncrement amount: Int) -> () -> Int {
        var runningTotal = 0
        func incrementer() -> Int {
            runningTotal += amount
            return runningTotal
        }
        return incrementer
    }

The return type of makeIncrementer is () -> Int. This means that it returns a function, rather than a simple value.
The makeIncrementer(forIncrement:) function has a single Int parameter with an external name of forIncrement, and a local name of amount. The argument value passed to this parameter specifies how much runningTotal should be incremented by each time the returned incrementer function is called.

Here’s an example of makeIncrementer and calling the function multiple times shows this behavior in action:

        let incrementByTen = makeIncrementer(forIncrement: 10)

    incrementByTen()
    // returns a value of 10
    incrementByTen()
    // returns a value of 20
    incrementByTen()
    // returns a value of 30

If you create a second incrementer, it will have its own stored reference to a new, separate runningTotal variable, calling the original incrementer (incrementByTen) again continues to increment its own runningTotal variable, and does not affect the variable captured by incrementBySeven:

    let incrementBySeven = makeIncrementer(forIncrement: 7)
    incrementBySeven()
    // returns a value of 7

    incrementByTen()
    // returns a value of 40

Closures Are Reference Types

上面的例子中,incrementBySeven和incrementByTen是常量,但是這些常量指向的Closure仍然可以增加其捕獲的變量的值。這是因為函數和Closure都是引用類型。
無論您將函數或閉包賦值給一個常量還是變量,您實際上都是將常量或變量的值設置為對應函數或Closure的引用。上面的例子中,指向Closure的引用incrementByTen是一個常量,而並非Closure內容本身。

Nonescaping Closures

A closure is said to escape a function when the closure is passed as an argument to the function, but is called after the function returns.

When you declare a function that takes a closure as one of its parameters, you can write @noescape before the parameter name to indicate that the closure is not allowed to escape.
Marking a closure with @noescape lets the compiler make more aggressive optimizations because it knows more information about the closure’s lifespan.

    func someFunctionWithNoescapeClosure(@noescape closure: () -> Void) {
        closure()
    }

一種能使Closure“逃逸”出函數的方法是,將這個Closure保存在一個函數外部定義的變量中。
As an example, many functions that start an asynchronous operation take a closure argument as a completion handler. The function returns after it starts the operation, but the closure isn’t called until the operation is completed—the closure needs to escape, to be called later.

    var completionHandlers: [() -> Void] = []
    func someFunctionWithEscapingClosure(completionHandler: () -> Void) {
        completionHandlers.append(completionHandler)
    }

If you tried to mark the parameter of above function with @noescape, you would get a compiler error.

Autoclosures

Autoclosures是一種自動創建的Closure,用於包裝傳遞給函數作為參數的表達式。這種閉包不接受任何參數,當它被調用的時候,會返回被包裝在其中的表達式的值。

Even though the first element of the customersInLine array is removed by the code inside the closure, the array element isn’t removed until the closure is actually called. If the closure is never called, the expression inside the closure is never evaluated, which means the array element is never removed.

    var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
    print(customersInLine.count)
    // prints "5"

    let customerProvider = { customersInLine.removeAtIndex(0) }
    print(customersInLine.count)
    // prints "5"

    print("Now serving \(customerProvider())!")
    // prints "Now serving Chris!"
    print(customersInLine.count)
    // prints "4"

You get the same behavior of delayed evaluation when you pass a closure as an argument to a function.

    // customersInLine is ["Alex", "Ewa", "Barry", "Daniella"]
    func serveCustomer(customerProvider: () -> String) {
        print("Now serving \(customerProvider())!")
    }
    serveCustomer( { customersInLine.removeAtIndex(0) } )
    // prints "Now serving Alex!"

It takes an autoclosure by marking its parameter with the @autoclosure attribute.

    // customersInLine is ["Ewa", "Barry", "Daniella"]
    func serveCustomer(@autoclosure customerProvider: () -> String) {
        print("Now serving \(customerProvider())!")
    }
    serveCustomer(customersInLine.removeAtIndex(0))
    // prints "Now serving Ewa!"

The @autoclosure attribute implies the @noescape attribute. If you want an autoclosure that is allowed to escape, use the @autoclosure(escaping) form of the attribute.

    // customersInLine is ["Barry", "Daniella"]
    var customerProviders: [() -> String] = []
    func collectCustomerProviders(@autoclosure(escaping) customerProvider: () -> String) {
        customerProviders.append(customerProvider)
    }
    collectCustomerProviders(customersInLine.removeAtIndex(0))
    collectCustomerProviders(customersInLine.removeAtIndex(0))

    print("Collected \(customerProviders.count) closures.")
    // prints "Collected 2 closures."
    for customerProvider in customerProviders {
        print("Now serving \(customerProvider())!")
    }
    // prints "Now serving Barry!"
    // prints "Now serving Daniella!"

In the code above, instead of calling the closure passed to it as its customer argument, the collectCustomerProviders(_:) function appends the closure to the customerProviders array. The array is declared outside the scope of the function, which means the closures in the array can be executed after the function returns. As a result, the value of the customer argument must be allowed to escape the function’s scope.

Enumerations

An enumeration defines a common type for a group of related values and enables you to work with those values in a type-safe way within your code.

Enumeration Syntax

You introduce enumerations with the enum keyword and place their entire definition within a pair of braces:

    enum SomeEnumeration {
        // enumeration definition goes here
    }

An example for the four main points of a compass:

    enum CompassPoint {
        case North
        case South
        case East
        case West
    }

Multiple cases can appear on a single line, separated by commas:

    enum Planet {
        case Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
    }

The type of directionToHead is inferred when it is initialized with one of the possible values of CompassPoint. Once directionToHead is declared as a CompassPoint, you can set it to a different CompassPoint value using a shorter dot syntax:

    var directionToHead = CompassPoint.West

        directionToHead = .East

Matching Enumeration Values with a Switch Statement

You can match individual enumeration values with a switch statement:

    directionToHead = .South
    switch directionToHead {
    case .North:
        print("Lots of planets have a north")
    case .South:
        print("Watch out for penguins")
    case .East:
        print("Where the sun rises")
    case .West:
        print("Where the skies are blue")
    }
    // prints "Watch out for penguins"

如果忽略了.West這種情況,上面那段代碼將無法通過編譯,因為它沒有考慮到CompassPoint的全部成員。強制窮舉確保了Enumerations成員不會被意外遺漏。

當不需要匹配每個Enumerations成員的時候,你可以提供一個default分支來涵蓋所有未明確處理的枚舉成員:

    let somePlanet = Planet.Earth
    switch somePlanet {
    case .Earth:
        print("Mostly harmless")
    default:
        print("Not a safe place for humans")
    }
    // prints "Mostly harmless"

Associated Values

You can define Swift enumerations to store associated values of any given type, and the value types can be different for each case of the enumeration if needed.

In Swift, an enumeration to define product barcodes of either type might look like this:

    enum Barcode {
        case UPCA(Int, Int, Int, Int)
        case QRCode(String)
    }

This can be read as:
“定義一個名為Barcode的enumeration type,它的一個成員值是具有(Int,Int,Int,Int)類型關聯值的UPCA,另一個成員值是具有String類型關聯值的QRCode。”

這裡的定義不提供任何Int或String類型的關聯值,它只是定義了,當Barcode常量和變量等於Barcode.UPCA或Barcode.QRCode時,可以存儲的關聯值的類型。

        var productBarcode = Barcode.UPCA(8, 85909, 51226, 3)
        productBarcode = .QRCode("ABCDEFGHIJKLMNOP")

可以使用一個switch 語句來檢查不同的條形碼類型。關聯值可以被提取出來作為switch 語句的一部分。
You can place a single var or let annotation before the case name, for brevity:

    switch productBarcode {
    case .UPCA(let numberSystem, let manufacturer, let product, let check):
        print("UPC-A: \(numberSystem), \(manufacturer), \(product), \(check).")
    case .QRCode(let productCode):
        print("QR code: \(productCode).")
    }
    // prints "QR code: ABCDEFGHIJKLMNOP."

如果一個enumeration成員的所有關聯值都被提取為常量,或者都被提取為變量,為了簡潔,你可以只在成員名稱前標註一個let或者var:

    switch productBarcode {
    case let .UPCA(numberSystem, manufacturer, product, check):
        print("UPC-A: \(numberSystem), \(manufacturer), \(product), \(check).")
    case let .QRCode(productCode):
        print("QR code: \(productCode).")
    }
    // prints "QR code: ABCDEFGHIJKLMNOP."

Raw Values

As an alternative to associated values, enumeration cases can come prepopulated with default values (called raw values), which are all of the same type.

Here’s an example that stores raw ASCII values alongside named enumeration cases:

    enum ASCIIControlCharacter: Character {
        case Tab = "\t"
        case LineFeed = "\n"
        case CarriageReturn = "\r"
    }

Enumeration類型ASCII Control Character的原始值類型被定義為Character,並設置了一些比較常見的ASCII 控制字符。 Character的描述詳見字符串和字符部分。

Raw values are not the same as associated values. Raw values are set to prepopulated values when you first define the enumeration in your code, like the three ASCII codes above. The raw value for a particular enumeration case is always the same. Associated values are set when you create a new constant or variable based on one of the enumeration’s cases, and can be different each time you do so.

Implicitly Assigned Raw Values

When you’re working with enumerations that store integer or string raw values, you don’t have to explicitly assign a raw value for each case. When you don’t, Swift will automatically assign the values for you.

        enum Planet: Int {
            case Mercury = 1, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
        }

In the example above, Planet.Mercury has an explicit raw value of 1, Planet.Venus has an implicit raw value of 2, and so on(以此類推, 等等).

    let sunsetDirection = CompassPoint.West.rawValue
    // sunsetDirection is "West"

Initializing from a Raw Value

If you define an enumeration with a raw-value type, the enumeration automatically receives an initializer that takes a value of the raw value’s type and returns either an enumeration case or nil. You can use this initializer to try to create a new instance of the enumeration.

    let possiblePlanet = Planet(rawValue: 7)
    // possiblePlanet is of type `Planet?` and equals Planet.Uranus

If you try to find a planet with a position of 9, the optional Planet value returned by the raw value initializer will be nil:

    let positionToFind = 9
    if let somePlanet = Planet(rawValue: positionToFind) {
        switch somePlanet {
        case .Earth:
            print("Mostly harmless")
        default:
            print("Not a safe place for humans")
        }
    } else {
        print("There isn't a planet at position \(positionToFind)")
    }
    // prints "There isn't a planet at position 9"

Recursive Enumerations

遞歸枚舉(recursive enumeration)是一種枚舉類型,它有一個或多個枚舉成員使用該枚舉類型的實例作為關聯值。使用遞歸枚舉時,編譯器會插入一個間接層。你可以在枚舉成員前加上indirect來表示該成員可遞歸。

    indirect enum ArithmeticExpression {
        case Number(Int)
        case Addition(ArithmeticExpression, ArithmeticExpression)
        case Multiplication(ArithmeticExpression, ArithmeticExpression)
    }

A recursive function is a straightforward way to work with data that has a recursive structure. For example, here’s a function that evaluates an arithmetic expression:

    func evaluate(expression: ArithmeticExpression) -> Int {
        switch expression {
        case .Number(let value):
            return value
        case .Addition(let left, let right):
            return evaluate(left) + evaluate(right)
        case .Multiplication(let left, let right):
            return evaluate(left) * evaluate(right)
        }
    }

    // evaluate (5 + 4) * 2
    let five = ArithmeticExpression.Number(5)
    let four = ArithmeticExpression.Number(4)
    let sum = ArithmeticExpression.Addition(five, four)
    let product = ArithmeticExpression.Multiplication(sum, ArithmeticExpression.Number(2))
    print(evaluate(product))
    // prints "18"

Classes and Structures

Classes and structures are general-purpose, flexible constructs that become the building blocks of your program’s code.

Note
An instance of a class is traditionally known as an object. However, Swift classes and structures are much closer in functionality than in other languages, and much of this chapter describes functionality that can apply to instances of either a class or a structure type. Because of this, the more general term instance is used.

Comparing Classes and Structures

Classes and structures in Swift have many things in common. Both can:
* Define properties to store values
* Define methods to provide functionality
* Define subscripts to provide access to their values using subscript syntax
* Define initializers to set up their initial state
* Be extended to expand their functionality beyond a default implementation
* Conform to protocols to provide standard functionality of a certain kind

Classes have additional capabilities that structures do not:
* Inheritance enables one class to inherit the characteristics of another.
* Type casting enables you to check and interpret the type of a class instance at runtime.
* Deinitializers enable an instance of a class to free up any resources it has assigned.
* Reference counting allows more than one reference to a class instance.

Definition Syntax

Classes and structures have a similar definition syntax. You introduce classes with the class keyword and structures with the struct keyword.

    class SomeClass {
        // class definition goes here
    }
    struct SomeStructure {
        // structure definition goes here
    }

Note
Whenever you define a new class or structure, you effectively define a brand new Swift type. Give types UpperCamelCase names (such as SomeClass and SomeStructure here) to match the capitalization of standard Swift types (such as String, Int, and Bool).
Conversely, always give properties and methods lowerCamelCase names (such as frameRate and incrementCount) to differentiate them from type names.

ex.

    struct Resolution {
        var width = 0
        var height = 0
    }
    class VideoMode {
        var resolution = Resolution()
        var interlaced = false
        var frameRate = 0.0
        var name: String?
    }

Class and Structure Instances

The Resolution structure definition and the VideoMode class definition only describe what a Resolution or VideoMode will look like.
They themselves do not describe a specific resolution or video mode. To do that, you need to create an instance of the structure or class.

    let someResolution = Resolution()
    let someVideoMode = VideoMode()

通過這種方式所創建的類或者結構體實例,其屬性均會被初始化為默認值。

Accessing Properties

You can access the properties of an instance using dot syntax. In dot syntax, you write the property name immediately after the instance name, separated by a period (.), without any spaces:

    print("The width of someResolution is \(someResolution.width)")
    // prints "The width of someResolution is 0"

Unlike structures, class instances do not receive a default memberwise initializer.

Memberwise Initializers for Structure Types

All structures have an automatically-generated memberwise initializer, which you can use to initialize the member properties of new structure instances. Initial values for the properties of the new instance can be passed to the memberwise initializer by name:

        let vga = Resolution(width: 640, height: 480)

Structures and Enumerations Are Value Types

A value type is a type whose value is copied when it is assigned to a variable or constant, or when it is passed to a function.

        let hd = Resolution(width: 1920, height: 1080)
        var cinema = hd

    cinema.width = 2048
    print("cinema is now \(cinema.width) pixels wide")
    // prints "cinema is now 2048 pixels wide"

    print("hd is still \(hd.width) pixels wide")
    // prints "hd is still 1920 pixels wide"

在將hd賦予給cinema的時候,實際上是將hd中所存儲的值進行拷貝,然後將拷貝的數據存儲到新的cinema實例中。結果就是兩個完全獨立的實例碰巧包含有相同的數值。由於兩者相互獨立,因此將cinema的width修改為2048並不會影響hd中的width的值。

Classes Are Reference Types

Unlike value types, reference types are not copied when they are assigned to a variable or constant, or when they are passed to a function.

    let tenEighty = VideoMode()
    tenEighty.resolution = hd
    tenEighty.interlaced = true
    tenEighty.name = "1080i"
    tenEighty.frameRate = 25.0

    //Assigned to a new constant
    let alsoTenEighty = tenEighty
    alsoTenEighty.frameRate = 30.0

        print("The frameRate property of tenEighty is now \(tenEighty.frameRate)")
        // 输出 "The frameRate property of theEighty is now 30.0"

因為類是Reference Type,所以tenEight和alsoTenEight實際上引用的是相同的VideoMode實例。換句話說,它們是同一個實例的兩種叫法。

Note that tenEighty and alsoTenEighty are declared as constants, rather than variables. However, you can still change tenEighty.frameRate and alsoTenEighty.frameRate because the values of the tenEighty and alsoTenEighty constants themselves do not actually change. tenEighty and alsoTenEighty themselves do not “store” the VideoMode instance—instead, they both refer to a VideoMode instance behind the scenes. It is the frameRate property of the underlying VideoMode that is changed, not the values of the constant references to that VideoMode.

Properties

Properties associate values with a particular class, structure, or enumeration.

Stored Properties

In its simplest form, a stored property is a constant or variable that is stored as part of an instance of a particular class or structure. Stored properties can be either variable stored properties (introduced by the var keyword) or constant stored properties (introduced by the let keyword).

    struct FixedLengthRange {
        var firstValue: Int
        let length: Int
    }
    var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3)
    // the range represents integer values 0, 1, and 2
    rangeOfThreeItems.firstValue = 6
    // the range now represents integer values 6, 7, and 8

Stored Properties of Constant Structure Instances

如果創建了一個結構體的實例並將其賦值給一個常量,則無法修改該實例的任何屬性,即使定義了變量存儲屬性.

    let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4)
    // this range represents integer values 0, 1, 2, and 3
    rangeOfFourItems.firstValue = 6
    // this will report an error, even though firstValue is a variable property

Because rangeOfFourItems is declared as a constant (with the let keyword), it is not possible to change its firstValue property, even though firstValue is a variable property.

Lazy Stored Properties

A lazy stored property is a property whose initial value is not calculated until the first time it is used.

Note
You must always declare a lazy property as a variable (with the var keyword), because its initial value might not be retrieved until after instance initialization completes. Constant properties must always have a value before initialization completes, and therefore cannot be declared as lazy.

Lazy properties are useful when the initial value for a property is dependent on outside factors whose values are not known until after an instance’s initialization is complete. Lazy properties are also useful when the initial value for a property requires complex or computationally expensive setup that should not be performed unless or until it is needed.

The example below uses a lazy stored property to avoid unnecessary initialization of a complex class.

    class DataImporter {
        /*
        DataImporter is a class to import data from an external file.
        The class is assumed to take a non-trivial amount of time to initialize.
        */
        var fileName = "data.txt"
        // the DataImporter class would provide data importing functionality here
    }

    class DataManager {
        lazy var importer = DataImporter()
        var data = [String]()
        // the DataManager class would provide data management functionality here
    }

    let manager = DataManager()
    manager.data.append("Some data")
    manager.data.append("Some more data")
    // the DataImporter instance for the importer property has not yet been created

    print(manager.importer.fileName)
    // the DataImporter instance for the importer property has now been created
    // prints "data.txt"

If a property marked with the lazy modifier is accessed by multiple threads simultaneously and the property has not yet been initialized, there is no guarantee that the property will be initialized only once.

Computed Properties

In addition to stored properties, classes, structures, and enumerations can define computed properties, which do not actually store a value. Instead, they provide a getter and an optional setter to retrieve and set other properties and values indirectly.

    struct Point {
        var x = 0.0, y = 0.0
    }
    struct Size {
        var width = 0.0, height = 0.0
    }
    struct Rect {
        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(newCenter) {
                origin.x = newCenter.x - (size.width / 2)
                origin.y = newCenter.y - (size.height / 2)
            }
        }
    }
    var square = Rect(origin: Point(x: 0.0, y: 0.0),
        size: Size(width: 10.0, height: 10.0))
    let initialSquareCenter = square.center
    square.center = Point(x: 15.0, y: 15.0)
    print("square.origin is now at (\(square.origin.x), \(square.origin.y))")
    // prints "square.origin is now at (10.0, 10.0)"

這個例子定義了3 個結構體來描述幾何形狀:
* Point封裝了一個(x, y)的坐標
* Size封裝了一個width和一個height
* Rect表示一個有原點和尺寸的矩形

The self Property

Every instance of a type has an implicit property called self, which is exactly equivalent to the instance itself.
可以在一個實例的實例方法中使用這個隱含的self屬性來引用當前實例。

        lass Counter {
            var count = 0
            func increment() {
                ++count
            }
            func incrementBy(amount: Int) {
                count += amount
            }
            func reset() {
                count = 0
            }
        }

    func increment() {
            self.count++
        }

Here, self disambiguates between a method parameter called x and an instance property that is also called x:

    struct Point {
        var x = 0.0, y = 0.0
        func isToTheRightOfX(x: Double) -> Bool {
            return self.x > x
        }
    }
    let somePoint = Point(x: 4.0, y: 5.0)
    if somePoint.isToTheRightOfX(1.0) {
        print("This point is to the right of the line where x == 1.0")
    }
    // prints "This point is to the right of the line where x == 1.0"

Without the self prefix, Swift would assume that both uses of x referred to the method parameter called x.

參考資料:
1. https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/index.html#//apple_ref/doc/uid/TP40014097-CH3-ID0
2. http://wiki.jikexueyuan.com/project/swift/

2015年12月8日 星期二

iOS筆記:Swift (2)

Collection Types

Swift 語言提供Arrays、Sets和Dictionaries三種基本的集合類型用來存儲集合數據。數組(Arrays)是有序數據的集。集合(Sets)是無序無重複數據的集。字典(Dictionaries)是無序的鍵值對的集。

enter image description here

Arrays

Arrays使用有序列表存儲同一類型的多個值。相同的值可以多次出現在一個數組的不同位置中。
The type of a Swift array is written in full as Array, where Element is the type of values the array is allowed to store.

Note that the type of the someInts variable is inferred to be [Int] from the type of the initializer.
ex. Creating an Empty Array:

    var someInts = [Int]()
    print("someInts is of type [Int] with \(someInts.count) items.")
    // prints "someInts is of type [Int] with 0 items."

    someInts.append(3)
        // someInts 現在包含一個 Int 值
        someInts = []
        // someInts 現在是空數組,但是仍然是[Int] 類型的。

ex. Creating an Array with a Default Value
Pass this initializer the number of items to be added to the new array (called count) and a default value of the appropriate type (called repeatedValue):

    var threeDoubles = [Double](count: 3, repeatedValue: 0.0)
    // threeDoubles is of type [Double], and equals [0.0, 0.0, 0.0]

    //Creating an Array by Adding Two Arrays Together
    var anotherThreeDoubles = [Double](count: 3, repeatedValue: 2.5) // [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]

ex. Creating an Array with an Array Literal

    var shoppingList: [String] = ["Eggs", "Milk"]
    // shoppingList has been initialized with two initial items

    for item in shoppingList {
    print(item)
}
// Eggs
// Milk

enumerate()返回一個由每一個數據項索引值和數據值組成的元組。

for (index, value) in shoppingList.enumerate() {
    print("Item \(index + 1): \(value)")
}
// Item 1: Eggs
// Item 2: Milk

Sets

Set用來存儲相同類型並且沒有確定順序的值。當集合元素順序不重要時或者希望確保每個元素只出現一次時可以使用集合而不是數組。

Swift’s Set type is bridged to Foundation’s NSSet class.

Hash Values for Set Types

A type must be hashable in order to be stored in a set—that is, the type must provide a way to compute a hash value for itself. A hash value is an Int value that is the same for all objects that compare equally, such that if a == b, it follows that a.hashValue == b.hashValue.

Set Type Syntax

Swift 中的Set類型被寫為Set,這裡的Element表示Set中允許存儲的類型,和數組不同的是,集合沒有等價的簡化形式。
ex. Creating and Initializing an Empty Set

    var letters = Set<Character>()
    print("letters is of type Set<Character> with \(letters.count) items.")
    // prints "letters is of type Set<Character> with 0 items."

    letters.insert("a")
    // letters now contains 1 value of type Character
    letters = []
    // letters is now an empty set, but is still of type Set<Character>

ex. Creating a Set with an Array Literal

    var favoriteGenres: Set<String> = ["Rock", "Classical", "Hip hop"]
    // favoriteGenres has been initialized with three initial items

Accessing and Modifying a Set

    print("I have \(favoriteGenres.count) favorite music genres.")
    // prints "I have 3 favorite music genres."

    if favoriteGenres.isEmpty {
        print("As far as music goes, I'm not picky.")
    } else {
        print("I have particular music preferences.")
    }
    // prints "I have particular music preferences."

a. Add a new item into a set by calling the set’s insert(_:) method.
b. Remove an item from a set by calling the set’s remove(_:) method.
c. To check whether a set contains a particular item, use the contains(_:) method.

Fundamental Set Operations

The illustration below depicts two sets–a and b– with the results of various set operations represented by the shaded regions.

enter image description here

a. 使用intersect(_:)方法根據兩個集合中都包含的值創建的一個新的集合。
b. 使用exclusiveOr(_:)方法根據在一個集合中但不在兩個集合中的值創建一個新的集合。
c. 使用union(_:)方法根據兩個集合的值創建一個新的集合。
d. 使用subtract(_:)方法根據不在該集合中的值創建一個新的集合。

   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).sort()
    // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    oddDigits.intersect(evenDigits).sort()
    // []
    oddDigits.subtract(singleDigitPrimeNumbers).sort()
    // [1, 9]
    oddDigits.exclusiveOr(singleDigitPrimeNumbers).sort()
    // [1, 2, 9]

Set Membership and Equality

    let houseAnimals: Set = ["dog", "cat"]
    let farmAnimals: Set = ["cow", "chicken", "Sheep", "dog", "cat"]
    let cityAnimals: Set = ["pigeon", "rat"]

    houseAnimals.isSubsetOf(farmAnimals)
    // true
    farmAnimals.isSupersetOf(houseAnimals)
    // true
    farmAnimals.isDisjointWith(cityAnimals)
    // true

Dictionaries

字典是一種存儲多個相同類型的值的容器。每個值(value)都關聯唯一的key.

Swift’s Dictionary type is bridged to Foundation’s NSDictionary class.

Dictionary Type Shorthand Syntax

Swift 的字典使用Dictionary<Key, Value>定義,其中Key是字典中鍵的數據類型,Value是字典中對應於這些鍵所存儲值的數據類型。也可以用[Key: Value]怎樣快捷的形式去創建一個字典類型。

Creating a Dictionary

    var namesOfIntegers = [Int: String]()
    // namesOfIntegers is an empty [Int: String] dictionary

    namesOfIntegers[16] = "sixteen"
    // namesOfIntegers now contains 1 key-value pair
    namesOfIntegers = [:]
    // namesOfIntegers is once again an empty dictionary of type [Int: String]

一個鍵值對是一個key和一個value的結合體。在字典字面量中,每一個鍵值對的鍵和值都由冒號分割。這些鍵值對構成一個列表,其中這些鍵值對由方括號包含、由逗號分割:
[key 1: value 1, key 2: value 2, key 3: value 3]

    var airports: [String: String] = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]

也可以使用以下宣告方式,Swift 可以推斷出Dictionary<String, String>是airports字典的正確類型。

    var airports = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]

Accessing and Modifying a Dictionary

大部分的用法同上述,The updateValue(_:forKey:) method returns an optional value of the dictionary’s value type.remove ValueForKey(_:)方法也可以用來在字典中移除鍵值對。這個方法在鍵值對存在的情況下會移除該鍵值對並且返回被移除的值或者在沒有值的情況下返回nil:

    if let oldValue = airports.updateValue("Dublin Airport", forKey: "DUB") {
        print("The old value for DUB was \(oldValue).")
    }
    // prints "The old value for DUB was Dublin."


    if let removedValue = airports.removeValueForKey("DUB") {
        print("The removed airport's name is \(removedValue).")
    } else {
        print("The airports dictionary does not contain a value for DUB.")
    }
    // prints "The removed airport's name is Dublin Airport."

FOR-IN method 1.

    for (airportCode, airportName) in airports {
        print("\(airportCode): \(airportName)")
    }
    // YYZ: Toronto Pearson
    // LHR: London Heathrow

Method 2.

    for airportCode in airports.keys {
        print("Airport code: \(airportCode)")
    }
    // Airport code: YYZ
    // Airport code: LHR

    for airportName in airports.values {
        print("Airport name: \(airportName)")
    }
    // Airport name: Toronto Pearson
    // Airport name: London Heathrow

Forloop

Swift 提供兩種for循環形式以來按照指定的次數多次執行一系列語句:

  • for-in循環對一個集合裡面的每個元素執行一系列語句。
  • for 循環,用來重複執行一系列語句直到達成特定條件達成,一般通過在每次循環完成後增加計數器的值來實現。

For-In

Example:

    for index in 1...5 {
        print("\(index) times 5 is \(index * 5)")
    }
    // 1 times 5 is 5
    // 2 times 5 is 10
    // 3 times 5 is 15
    // 4 times 5 is 20
    // 5 times 5 is 25

如果不需要知道區間序列內每一項的值,你可以使用下劃線(_)替代變量名來忽略對值的訪問:

    let base = 3
    let power = 10
    var answer = 1
    for _ in 1...power {
        answer *= base
    }
    print("\(base) to the power of \(power) is \(answer)")
    // prints "3 to the power of 10 is 59049"
    let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
    for (animalName, legCount) in numberOfLegs {
        print("\(animalName)s have \(legCount) legs")
    }
    // ants have 6 legs
    // cats have 4 legs
    // spiders have 8 legs

Swift supports traditional C-style for loops with a condition and an incrementer:

    for var index = 0; index < 3; ++index {
        print("index is \(index)")
    }
    // index is 0
    // index is 1
    // index is 2

While Loops

while循環運行一系列語句直到條件變成false。這類循環適合使用在第一次迭代前迭代次數未知的情況下。 Swift 提供兩種while循環形式:

  • while循環,每次在循環開始時計算條件是否符合;
  • repeat-while循環,每次在循環結束時計算條件是否符合。

while循環從計算單一條件開始。如果條件為true,會重複運行一系列語句,直到條件變為false。

    while condition {
        statements
    }
        var square = 0
        var diceRoll = 0
        while square < finalSquare {
            // roll the dice
            if ++diceRoll == 7 { diceRoll = 1 }
            // move by the rolled amount
           square += diceRoll
          if square < board.count {
                // if we're still on the board, move up or down for a snake or a ladder
                square += board[square]
            }
        }

while循環的另外一種形式是repeat-whil​​e,它和while的區別是在判斷循環條件之前,先執行一次循環的代碼塊,然後重複循環直到條件為false。

The repeat-while loop in Swift is analogous to a do-while loop in other languages.

        repeat {
            statements
        } while condition
    repeat {
        // move up or down for a snake or ladder
        square += board[square]
        // roll the dice
        if ++diceRoll == 7 { diceRoll = 1 }
        // move by the rolled amount
        square += diceRoll
    } while square < finalSquare
    print("Game over!")

Conditional Statements

if-else

    temperatureInFahrenheit = 90
    if temperatureInFahrenheit <= 32 {
        print("It's very cold. Consider wearing a scarf.")
    } else if temperatureInFahrenheit >= 86 {
        print("It's really warm. Don't forget to wear sunscreen.")
    } else {
        print("It's not that cold. Wear a t-shirt.")
    }
    // prints "It's really warm. Don't forget to wear sunscreen."

Switch
switch語句會嘗試把某個值與若干個模式(pattern)進行匹配。根據第一個匹配成功的模式,switch語句會執行對應的代碼。當有可能的情況較多時,通常用switch語句替換if語句。

No Implicit Fallthrough
與C 語言和Objective-C 中的switch語句不同,在Swift 中,當匹配的case 分支中的代碼執行完畢後,程序會終止switch語句,而不會繼續執行下一個case 分支。這也就是說,不需要在case 分支中顯式地使用break語句。這使得switch語句更安全、更易用,也避免了因忘記寫break語句而產生的錯誤。

Although break is not required in Swift, you can still use a break statement to match and ignore a particular case, or to break out of a matched case before that case has completed its execution.

    let anotherCharacter: Character = "a"
    switch anotherCharacter {
    case "a":
    case "A":
        print("The letter A")
    default:
        print("Not the letter A")
    }
    // this will report a compile-time error

case 分支的模式也可以是一個值的區間。

    let approximateCount = 62
    let countedThings = "moons orbiting Saturn"
    var naturalCount: String
    switch approximateCount {
    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).")
    // prints "There are dozens of moons orbiting Saturn."

使用Tuple在同一個switch語句中測試多個值。Tuple中的元素可以是值,也可以是區間。另外,使用下劃線(_)來匹配所有可能的值。

    let somePoint = (1, 1)
    switch somePoint {
    case (0, 0):
        print("(0, 0) is at the origin")
    case (_, 0):
        print("(\(somePoint.0), 0) is on the x-axis")
    case (0, _):
        print("(0, \(somePoint.1)) is on the y-axis")
    case (-2...2, -2...2):
        print("(\(somePoint.0), \(somePoint.1)) is inside the box")
    default:
        print("(\(somePoint.0), \(somePoint.1)) is outside of the box")
    }
    // prints "(1, 1) is inside the box"

Where
case 分支的模式可以使用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")
    }
    // prints "(1, -1) is on the line x == -y"

Control Transfer Statements

  1. continue語句告訴一個循環體立刻停止本次循環迭代,重新開始下次循環迭代。就好像在說“本次循環迭代我已經執行完了”,但是並不會離開整個循環體。
    let puzzleInput = "great minds think alike"
    var puzzleOutput = ""
    for character in puzzleInput.characters {
        switch character {
        case "a", "e", "i", "o", "u", " ":
            continue
        default:
            puzzleOutput.append(character)
        }
    }
    print(puzzleOutput)
    // prints "grtmndsthnklk"
  1. break語句會立刻結束整個控制流的執行。
    當在一個循環體中使用break時,會立刻中斷該循環體的執行,然後跳轉到表示循環體結束的大括號(})後的第一行代碼。不會再有本次循環迭代的代碼被執行,也不會再有下次的循環迭代產生。

  2. Fallthrough
    這個例子定義了一個String類型的變量description並且給它設置了一個初始值。函數使用switch邏輯來判斷integerToDescribe變量的值。當integerToDescribe的值屬於列表中的質數之一時,該函數添加一段文字在description後,來表明這個是數字是一個質數。然後它使用fallthrough關鍵字來“貫穿”到default分支中。 default分支添加一段額外的文字在description的最後,至此switch代碼塊執行完了。

    let integerToDescribe = 5
    var description = "The number \(integerToDescribe) is"
    switch integerToDescribe {
    case 2, 3, 5, 7, 11, 13, 17, 19:
        description += " a prime number, and also"
        fallthrough
    default:
        description += " an integer."
    }
    print(description)
    // prints "The number 5 is a prime number, and also an integer."

The fallthrough keyword does not check the case conditions for the switch case that it causes execution to fall into. The fallthrough keyword simply causes code execution to move directly to the statements inside the next case (or default case) block, as in C’s standard switch statement behavior.

  1. Early Exit
    像if語句一樣,guard的執行取決於一個表達式的 Boolean value。一個guard語句總是有一個else分句,如果條件不為真則執行else分句中的代碼。
    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(["name": "John"])
    // prints "Hello John!"
    // prints "I hope the weather is nice near you."
    greet(["name": "Jane", "location": "Cupertino"])
    // prints "Hello Jane!"
    // prints "I hope the weather is nice in Cupertino."

Checking API Availability

Swift has built-in support for checking API availability, which ensures that you don’t accidentally use APIs that are unavailable on a given deployment target.

    if #available(iOS 9, OSX 10.10, *) {
        // Use iOS 9 APIs on iOS, and use OS X v10.10 APIs on OS X
    } else {
        // Fall back to earlier iOS and OS X APIs
    }

Defining and Calling Functions

在下面例子中的函數叫做”sayHello(_:)”,這個函數用一個人的名字當做輸入,並返回給這個人的問候語。為了完成這個任務,你定義一個輸入參數-一個叫做personName 的String 值,和一個包含給這個人問候語的String 類型的返回值:

    func sayHello(personName: String) -> String {
        let greeting = "Hello, " + personName + "!"
        return greeting
    }

    print(sayHello("Anna"))
    // prints "Hello, Anna!"

Functions Without Parameters

儘管這個函數沒有參數,但是定義中在函數名後還是需要一對圓括號。當被調用時,也需要在函數名後寫一對圓括號。

    func sayHelloWorld() -> String {
        return "hello, world"
    }
    print(sayHelloWorld())
    // prints "hello, world"

Functions With Multiple Parameters

    func sayHello(personName: String, alreadyGreeted: Bool) -> String {
        if alreadyGreeted {
            return sayHelloAgain(personName)
        } else {
            return sayHello(personName)
        }
    }
    print(sayHello("Tim", alreadyGreeted: true))
    // prints "Hello again, Tim!"

Functions Without Return Values

    func printAndCount(stringToPrint: String) -> Int {
        print(stringToPrint)
        return stringToPrint.characters.count
    }
    func printWithoutCounting(stringToPrint: String) {
        printAndCount(stringToPrint)
    }
    printAndCount("hello, world")
    // prints "hello, world" and returns a value of 12
    printWithoutCounting("hello, world")
    // prints "hello, world" but does not return a value

Functions with Multiple Return Values

You can use a tuple type as the return type for a function to return multiple values as part of one compound return value.

    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)
    }

Optional Tuple Return Types

如果函數返回的元組類型有可能整個元組都“沒有值”,你可以使用可選的(Optional) 元組返回類型反映整個元組可以是nil的事實。

    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([8, -6, 2, 109, 3, 71]) {
        print("min is \(bounds.min) and max is \(bounds.max)")
    }
    // prints "min is -6 and max is 109"

Specifying External Parameter Names

        func sayHello(to person: String, and anotherPerson: String) -> String {
            return "Hello \(person) and \(anotherPerson)!"
        }
        print(sayHello(to: "Bill", and: "Ted"))
        // prints "Hello Bill and Ted!"

Default Parameter Values

    func someFunction(parameterWithDefault: Int = 12) {
        // function body goes here
        // if no arguments are passed to the function call,
        // value of parameterWithDefault is 12
    }
    someFunction(6) // parameterWithDefault is 6
    someFunction() // parameterWithDefault is 12

Variadic Parameters

一個可變參數(variadic parameter)可以接受零個或多個值。函數調用時,你可以用可變參數來指定函數參數可以被傳入不確定數量的輸入值。通過在變量類型名後面加入(…)的方式來定義可變參數。

A function may have at most one variadic parameter.

    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

Constant and Variable Parameters

Function parameters are constants by default. Trying to change the value of a function parameter from within the body of that function results in a compile-time error.

Define variable parameters by prefixing the parameter name with the var keyword:

    func alignRight(var string: String, totalLength: Int, pad: Character) -> String {
        let amountToPad = totalLength - string.characters.count
        if amountToPad < 1 {
            return string
        }
        let padString = String(pad)
        for _ in 1...amountToPad {
            string = padString + string
        }
        return string
    }
    let originalString = "hello"
    let paddedString = alignRight(originalString, totalLength: 10, pad: "-")
    // paddedString is equal to "-----hello"
    // originalString is still equal to "hello"

In-Out Parameters

變量參數,正如上面所述,僅能在函數體內被更改。如果你想要一個函數可以修改參數的值,並且想要在這些修改在函數調用結束後仍然存在,那麼就應該把這個參數定義為輸入輸出參數(In-Out Parameters)。

In-out parameters cannot have default values, and variadic parameters cannot be marked as inout. If you mark a parameter as inout, it cannot also be marked as var or let.

    func swapTwoInts(inout a: Int, inout _ b: 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"

Function Types

Every function has a specific function type, made up of the parameter types and the return type of the function.

    func addTwoInts(a: Int, _ b: Int) -> Int {
        return a + b
    }
    func multiplyTwoInts(a: Int, _ b: Int) -> Int {
        return a * b
    }

這兩個函數的類型是(Int, Int) -> Int,可以解讀為“A function type that has two parameters, both of type Int, and that returns a value of type Int.”。

Using Function Types

You use function types just like any other types in Swift.

    var mathFunction: (Int, Int) -> Int = addTwoInts

This can be read as:

“Define a variable called mathFunction, which has a type of ‘a function that takes two Int values, and returns an Int value.’ Set this new variable to refer to the function called addTwoInts.”

    print("Result: \(mathFunction(2, 3))")
    // prints "Result: 5"

As with any other type, you can leave it to Swift to infer the function type when you assign a function to a constant or variable:

    let anotherMathFunction = addTwoInts
    // anotherMathFunction is inferred to be of type (Int, Int) -> Int

Function Types as Parameter Types

可以用(Int, Int) -> Int這樣的函數類型作為另一個函數的參數類型。這樣你可以將函數的一部分實現留給函數的調用者來提供。

    func printMathResult(mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) {
        print("Result: \(mathFunction(a, b))")
    }
    printMathResult(addTwoInts, 3, 5)
    // prints "Result: 8"

這個例子定義了printMathResult(::_:) 函數,它有三個參數:第一個參數叫mathFunction,類型是(Int, Int) -> Int,你可以傳入任何這種類型的函數;第二個和第三個參數叫a 和b,它們的類型都是Int

Function Types as Return Types

You can use a function type as the return type of another function. You do this by writing a complete function type immediately after the return arrow (->) of the returning function.

    func stepForward(input: Int) -> Int {
        return input + 1
    }
    func stepBackward(input: Int) -> Int {
        return input - 1
    }

Here’s a function called chooseStepFunction(_:), whose return type is “a function of type (Int) -> Int”.

    func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
        return backwards ? stepBackward : stepForward
    }
var currentValue = 3
let moveNearerToZero = chooseStepFunction(currentValue > 0)
// moveNearerToZero now refers to the stepBackward() function

print("Counting to zero:")
// Counting to zero:
while currentValue != 0 {
    print("\(currentValue)... ")
    currentValue = moveNearerToZero(currentValue)
}
print("zero!")
// 3...
// 2...
// 1...
// zero!

Nested Functions

到目前為止所見到的所有函數都叫全局函數(global functions),它們定義在全局域中。你也可以把函數定義在別的函數體中,稱作嵌套函數(nested functions)。

嵌套函數是對外界不可見的,但是可以被它們的外圍函數(enclosing function)調用。

func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
    func stepForward(input: Int) -> Int { return input + 1 }
    func stepBackward(input: Int) -> Int { return input - 1 }
    return backwards ? stepBackward : stepForward
}
var currentValue = -4
let moveNearerToZero = chooseStepFunction(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!

參考資料:
1. https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/index.html#//apple_ref/doc/uid/TP40014097-CH3-ID0
2. http://wiki.jikexueyuan.com/project/swift/