The Swift Programming Language (Swift 2.2) Note

A Swift Tour

Values are never implicitly converted to another type.

There’s an even simpler way to include values in strings: Write the value in parentheses, and write a backslash () before the parentheses. For example:

let apples = 3
let oranges = 5
let appleSummary = "I have \(apples) apples."
let fruitSummary = "I have \(apples + oranges) pieces of fruit."

Create arrays and dictionaries using brackets ([]):

var occupations = [
   "Malcolm": "Captain",
   "Kaylee": "Mechanic",
]
occupations["Jayne"] = "Public Relations"

To create an empty array or dictionary, use the initializer syntax.

let emptyArray = [String]()
let emptyDictionary = [String: Float]()

If type information can be inferred, you can write an empty array as [] and an empty dictionary as [:].

shoppingList = []
occupations = [:]

Work Flow

You can use if and let together to work with values that might be missing.

var optionalName: String? = "John Appleseed"
var greeting = "Hello!"
if let name = optionalName {
        greeting = "Hello, \(name)"
}

Another way to handle optional values is to provide a default value using the ?? operator. If the optional value is missing, the default value is used instead.

//let nickName: String? = nil
let nickName: String? = "Bob"
let fullName: String = "John Appleseed"
let informalGreeting = "Hi \(nickName ?? fullName)"

Switches support any kind of data and a wide variety of comparison operations—they aren’t limited to integers and tests for equality.

let vegetable = "red pepper"
switch vegetable {
    case "celery":
        print("Add some raisins and make ants on a log.")
    case "cucumber", "watercress":
        print("That would make a good tea sandwich.")
    case let x where x.hasSuffix("pepper"):
        print("Is it a spicy \(x)?")
    default:
        print("Everything tastes good in soup.")
}

You can keep an index in a loop by using ..< to make a range of indexes. Use ..< to make a range that omits its upper value, and use … to make a range that includes both values.

var total = 0
for i in 0..<4 {
    total += i
}
print(total)

Functions and Closures

func greet(name: String, day: String) -> String {
return "Hello \(name), today is \(day)."
}
greet("Bob", day: "Tuesday")

Use a tuple to make a compound value—for example, to return multiple values from a function. The elements of a tuple can be referred to either by name or by number.

func calculateStatistics(scores: [Int]) -> (min: Int, max: Int, sum: Int) {
    // ...
    return (min, max, sum)
}
let statistics = calculateStatistics([5, 3, 100, 3, 9])
print(statistics.sum)
print(statistics.2)

Functions can also take a variable number of arguments, collecting them into an array.

func sumOf(numbers: Int...) -> Int {
    var sum = 0
    for number in numbers {
        sum += number
    }
    return sum
}
sumOf()
sumOf(42, 597, 12)

Functions are actually a special case of closures: blocks of code that can be called later. The code in a closure has access to things like variables and functions that were available in the scope where the closure was created, even if the closure is in a different scope when it is executed—you saw an example of this already with nested functions. You can write a closure without a name by surrounding code with braces ({}). Use in to separate the arguments and return type from the body.

//? 不太懂耶

Objects and Classes

Every property needs a value assigned—either in its declaration (as with numberOfSides) or in the initializer (as with name).

class NamedShape {
    var numberOfSides: Int = 0
    var name: String  // name property 是在 init 里赋值的

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

    func simpleDescription() -> String {
       return "A shape with \(numberOfSides) sides."
    }
}

Methods on a subclass that override the superclass’s implementation are marked with override—overriding a method by accident, without override, is detected by the compiler as an error. The compiler also detects methods with override that don’t actually override any method in the superclass. 比 python 严谨的地方。

Every property needs a value assigned—either in its declaration (as with numberOfSides) or in the initializer (as with name).

If you don’t need to compute the property but still need to provide code that is run before and after setting a new value, use willSet and didSet. The code you provide is run any time the value changes outside of an initializer. For example, the class below ensures that the side length of its triangle is always the same as the side length of its square.

class TriangleAndSquare {
    var triangle: EquilateralTriangle {
        willSet {
            square.sideLength = newValue.sideLength
        }
    }
    var square: Square {
        willSet {
            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")
print(triangleAndSquare.square.sideLength)
print(triangleAndSquare.triangle.sideLength)
triangleAndSquare.square = Square(sideLength:  50, name: "larger square")
print(triangleAndSquare.triangle.sideLength)

Enumerations and Structures

为什么这个栗子里,rankKing 是一个 optional 类型:

let rankKing = Rank(rawValue: 13)
rankKing?.simpleDescription()

Inside the switch, the enumeration case is referred to by the abbreviated form .Hearts because the value of self is already known to be a suit. You can use the abbreviated form anytime the value’s type is already known. // swift 为了减少代码量所做的工作。但是同一件事情用不同的语法表示,感觉并不清晰一致简单。

Use struct to create a structure. Structures support many of the same behaviors as classes, including methods and initializers. One of the most important differences between structures and classes is that structures are always copied when they are passed around in your code, but classes are passed by reference.

Classes and Structures

Structures and Enumerations Are Value Types

In fact, all of the basic types in Swift—integers, floating-point numbers, Booleans, strings, arrays and dictionaries—are value types, and are implemented as structures behind the scenes. All structures and enumerations are value types in Swift.

Classes Are Reference Types

This behavior is different from Foundation: NSString, NSArray, and NSDictionary are implemented as classes, not structures.

Identity Operators

“Equal to” means that two instances are considered “equal” or “equivalent” in value, for some appropriate meaning of “equal”, as defined by the type’s designer.

Properties

Stored Properties of Constant Structure Instances

This behavior is due to structures being value types. When an instance of a value type is marked as a constant, so are all of its properties. The same is not true for classes, which are reference types. If you assign an instance of a reference type to a constant, you can still change that instance’s variable properties.

Lazy Stored Properties

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.

Global and Local Variables

Global constants and variables are always computed lazily, in a similar manner to Lazy Stored Properties. Unlike lazy stored properties, global constants and variables do not need to be marked with the lazymodifier. Local constants and variables are never computed lazily.

// 天使啊

Type Property Syntax

For computed type properties for class types, you can use the class keyword instead to allow subclasses to override the superclass’s implementation.

好奇怪的关键词 class

class SomeClass {
    static var storedTypeProperty = "Some value."
    static var computedTypeProperty: Int {
        return 27
    }
    class var overrideableComputedTypeProperty: Int {
        return 107
    }
}