本文为已归档的历史博客内容,其内容可能随着时间发生已经改变。
This article is archived from my previous blog, so the content maybe have changed now.


Based on [The Swift Programming Language](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/) Swift 2 Edition

Intro: This document couldn’t be absolutely correct. Please tell me about the mistakes. Skip Welcome to Swift.

Info:


Language Guide


Enumerations

Enumerations in Swift are first-class types in their own right. They adopt many features traditionally supported only by classes, such as computed properties to provide additional information about the enumeration’s current value, and instance methods to provide functionality related to the values the enumeration represents. Enumerations can also define initializers to provide an initial member value; can be extended to expand their functionality beyond their original implementation; and can conform to protocols to provide standard functionality.

Enumeration Syntax && Matching Enumeration Values with a Switch Statement

In the CompassPoint example above, North, South, East and West do not implicitly equal 0, 1, 2 and 3. Instead, the different enumeration members are fully-fledged values in their own right, with an explicitly-defined type of CompassPoint.

In Swift, their names (such as CompassPoint) should start with a capital letter.

enum bestWebsites {
    case v2ex, dgtle, sspai, maimieng
}

var bw = bestWebsites.v2ex
bw = .maimieng
switch bw {
case .v2ex:
    print("Way to explore.")
case .dgtle:
    print("About digtle life.")
case .sspai:
    print("About news of iOS & Android.")
case .maimieng:
    print("My blog")
}

Associated Values

enum Apple {
    case hardware(String, Int, String)
    case software(String, Int)
}

var product2015 = Apple.hardware("iPhone", 5288, "16 G")
product2015 = .software("Apple Music", 10)

switch product2015 {
case .hardware(let productName, let price, let deviceRom):
    print("The device name is \(productName), the price is \(price), the device rom is \(deviceRom).")
case var .software(productName, feesPerMonth):
    print("The software name is \(productName), the fees per month is \(feesPerMonth)¥.")
}

// DISPLAY:
// The software name is Apple Music, the fees per month is 10¥.

Raw Values

Associated values are set when you create a new constant or variable based on one of the enumeration’s members, and can be different each time you do so.

enum platformOfProgrammingLanguage: String {
    case Android =  "Java"
    case iOS = "Swift"
}

Implicitly Assigned Raw Values & Initializing from a Raw Value

enum platformOfProgrammingLanguage: String {
    case Android
    case iOS
}

print(platformOfProgrammingLanguage.iOS.rawValue)
print(platformOfProgrammingLanguage(rawValue: "C++"))

// DISPLAY:
// iOS
// nil

Recursive Enumerations



Closures

Global functions are closures that have a name and do not capture any values. Nested functions are closures that have a name and can capture values from their enclosing function. Closure expressions are unnamed closures written in a lightweight(adj.轻便的) syntax that can capture values from their surrounding context.

Closure Expressions

let website = ["v2ex", "maimieng", "apple", "github"]
The Sort Method
func test1(s1: String, s2: String) -> Bool {
    return s1 > s2
}

print(website.sort(test1))

// DISPLAY:
// ["v2ex", "maimieng", "github", "apple"]
Closure Expression Syntax

{ (parameters) -> returnType in statements }

var p = website.sort({ (s1: String, s2: String) -> Bool in
    return s1 > s2
})
Inferring Type From Context
var p = website.sort( { s1, s2 in return s1 > s2 } )```

##### Implicit Returns from Single-Expression Closures

swift var p = website.sort( { s1, s2 in s1 > s2 } )


##### Shorthand Argument Names

swift var p = website.sort( { $0 > $1 } )


##### Operator Functions

swift var p = website.sort(>)


#### Trailing(`v.跟踪`) Closures

swift var p = website.sort() { $0 > $1 }

var q = website.sort { $0 > $1 }


swift 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]

var s = numbers.map { (var number) -> String in var output = “” while number > 0 { output = digitNames[number % 10]! + output number /= 10 } return output }

print(s)

// DISPLAY: // [“OneSix”, “FiveEight”, “FiveOneZero”]


#### Capturing Values & Closures Are Reference Types

swift func makeIncrementor(forIncrement amount: Int) -> () -> Int { var runningTotal = 0 func incrementor() -> Int { runningTotal += amount return runningTotal } return incrementor } let incrementByTen = makeIncrementor(forIncrement: 10) let incrementBySeven = makeIncrementor(forIncrement: 7) let alsoIncrementByTen = incrementByTen

print(makeIncrementor(forIncrement: 10)()) print(makeIncrementor(forIncrement: 10)()) print(incrementByTen()) print(incrementByTen())

print(incrementBySeven()) print(incrementBySeven())

print(incrementByTen())

print(alsoIncrementByTen())

// DISPLAY: // 10 // 10 // 10 // 20 // 7 // 14 // 30 // 40


#### Autoclosures

**DIFFICULT TO UNDERSTAND!**

An autoclosure lets you delay evaluation, because the code inside isn’t run until you call the closure.

swift var customersInLine = [“Chris”, “Alex”, “Ewa”, “Barry”, “Daniella”] let nextCustomer = { customersInLine.removeAtIndex(0) } print(customersInLine.count)

print(“Now serving (nextCustomer())!“) print(customersInLine.count)

func serveNextCustomer(customer: () -> String) { print(“Now serving (customer())!“) } serveNextCustomer( { customersInLine.removeAtIndex(0) } ) print(customersInLine.count)

func serveNextCustomer(@autoclosure customer: () -> String) { print(“Now serving (customer())!“) } serveNextCustomer(customersInLine.removeAtIndex(0)) print(customersInLine.count)

var customerClosures: [() -> String] = [] func collectCustomerClosures(@autoclosure(escaping) customer: () -> String) { customerClosures.append(customer) } collectCustomerClosures(customersInLine.removeAtIndex(0)) collectCustomerClosures(customersInLine.removeAtIndex(0))

print(“Collected (customerClosures.count) closures.“)

for customerClosure in customerClosures { print(“Now serving (customerClosure())!“) }

// DISPLAY: // 5 // Now serving Chris! // 4 // Now serving Alex! // 3 // Now serving Ewa! // 2 // Collected 2 closures. // Now serving Barry! // Now serving Daniella!


---

### Functions

#### Defining and Calling Functions

swift func website(a: String) -> String { return “http://” + a + “.com” }

print(website(“maimieng”))

// DISPLAY: // http://maimieng.com


#### Function Parameters and Return Values

##### Functions Without Parameters

swift func sayHelloWorld() -> String { return “hello, world” } print(sayHelloWorld())

// DISPLAY: // hello, world


#### Functions With Multiple Parameters

When calling a function with more than one parameter, any argument after the first is **labeled** according to its corresponding parameter name. 

swift func swap(a: Int, b: Int) -> (Int, Int) { return (b, a) }

print(swap(1, b: 2))

// DISPLAY: // (2, 1)


##### Functions Without Return Values

swift func spell(s: String) { for c in s.characters { print© } }

print(spell(“iOS”))

// DISPLAY: // i // O // S // ()

func count(s: String) -> Int { return s.characters.count }

func c(s: String) { count(s) }

print(count(“Swift”)) print(c(“Swift”))

// DISPLAY: // 5 // ()


##### Functions with Multiple Return Values & Optional Tuple Return Types

swift func findMinMax(array: [Int]) -> (min: Int, max: Int)? { if array.isEmpty { return nil } var cMin = array[0] var cMax = array[0] for value in array[1.. cMax { cMax = value } } return (cMin, cMax) }

print(findMinMax([3, 1, 4, 1, 5, 9])) print(findMinMax([]))

// DISPLAY: // Optional((1, 9)) // nil


#### Function Parameter Names

##### Specifying External Parameter Names

If you provide an external parameter name for a parameter, that external name must *always* be used when you call the function.

swift func sayHello(to person: String, and anotherPerson: String) -> String { return “Hello (person) and (anotherPerson)!” } print(sayHello(to: “Bill”, and: “Ted”))

// DISPLAY: // Hello Bill and Ted!


##### Omitting External Parameter Names

Because the first parameter omits its external parameter name by default, explicitly writing an underscore is extraneous(`adj.无关的`).

swift func someFunction(firstParameterName: Int, _ secondParameterName: Int) { } someFunction(1, 2)


##### Default Parameter Values

swift func test(a: Int = 1) { print(a) }

test() test(5)

// DISPLAY: // 1 // 5


##### Variadic(`adj.可变的`) Parameters

A function may have at most one variadic parameter.

swift func total(numbers: Double…) -> Double { var t: Double = 0 for n in numbers { t += n } return t / Double(numbers.count) } print(total(1, 2, 3, 4, 5)) print(total(3, 8.25, 18.75))

// DISPLAY: // 3.0 // 10.0


##### Constant and Variable Parameters

swift func website(var s: String) -> String { s += “.com” return s }

print(website(“maimieng”))

// DISPLAY: // maimieng.com


##### 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`.

swift func swap(inout a: Int, inout b: Int) { let t = a a = b b = t }

var a = 1 var b = 2 swap(&a, &b)

print(“((a), (b))“)

// DISPLAY: // (2, 1)


#### Function Types

##### Using Function Types

swift func total(a: Int, _ b: Int) -> Int { return a + b }

var t: (Int, Int) -> Int = total var tl = total

print(t(1, 1)) print(tl(2, 2))

// DISPLAY: // 2 // 4


##### Function Types as Parameter Types

swift func total(a: Int, _ b: Int) -> Int { return a + b }

func printT(total: (Int, Int) -> Int, _ a: Int, _ b: Int) { print(total(a, b)) }

printT(total, 1, 1)

// DISPLAY: // 2


##### Function Types as Return Types

swift func com(var a: String) -> String { a += “.com” return a }

func http(a: String) -> String { let b = “http://” + a return b }

func website(a: String) -> String { if !a.hasPrefix(“http://“) { return http(a) } if !a.hasSuffix(“.com”) { return com(a) } return “CORRECT” }

print(website(“http://maimieng"))

// DISPLAY: // http://maimieng.com


#### Nested Functions

Nested functions are hidden from the outside world by default, but can still be called and used by their enclosing function. An enclosing function can also return one of its nested functions to allow the nested function to be used in another scope.


swift func website(a: String) -> String {

func http(a: String) -> String {
    let b = "http://" + a
    return b
}

func com(var a: String) -> String {
    a += ".com"
    return a
}

if !a.hasPrefix("http://") {
    return http(a)
}
if !a.hasSuffix(".com") {
    return com(a)
}
return "CORRECT"

}

print(website(“http://maimieng"))

// DISPLAY: // http://maimieng.com


---

### Control Flow

#### For Loops

##### For-In & For

swift // 1…9 equals to 1..<10 for i in 1...9 { for j in 1...9 { if (i >= j) { print(”(j) * (i) = (i * j) “, terminator: “”) } } print(“”) } // DISPLAY: // 1 * 1 = 1 // 1 * 2 = 2 2 * 2 = 4 // 1 * 3 = 3 2 * 3 = 6 3 * 3 = 9 // 1 * 4 = 4 2 * 4 = 8 3 * 4 = 12 4 * 4 = 16 // 1 * 5 = 5 2 * 5 = 10 3 * 5 = 15 4 * 5 = 20 5 * 5 = 25 // 1 * 6 = 6 2 * 6 = 12 3 * 6 = 18 4 * 6 = 24 5 * 6 = 30 6 * 6 = 36 // 1 * 7 = 7 2 * 7 = 14 3 * 7 = 21 4 * 7 = 28 5 * 7 = 35 6 * 7 = 42 7 * 7 = 49 // 1 * 8 = 8 2 * 8 = 16 3 * 8 = 24 4 * 8 = 32 5 * 8 = 40 6 * 8 = 48 7 * 8 = 56 8 * 8 = 64 // 1 * 9 = 9 2 * 9 = 18 3 * 9 = 27 4 * 9 = 36 5 * 9 = 45 6 * 9 = 54 7 * 9 = 63 8 * 9 = 72 9 * 9 = 81


swift var i = 0 for _ in 1…5 { print(i++) }

for var a = 0; a < 3; a++ { print(a) }

// DISPLAY: // 0 // 1 // 2 // 3 // 4 // 0 // 1 // 2


#### While Loops

##### While & Repeat-While

swift var i = 0 while (i++ < 3) { print(i) }

var i = 0 repeat { print(i) } while (i++ < 3)

// DISPLAY: // 1 // 2 // 3 // 0 // 1 // 2 // 3


#### Conditional Statements

##### If

Omitted.

##### Switch

swift let c: Character = “i” switch c { case “a”, “e”, “i”, “o”, “u”: print(“c is a vowel.”) default: print(“c is not a vowel.”) }


###### No Implicit Fallthrough

Omitted.

###### Interval Matching

swift let a = 123 switch a { case 1…9: print(“a is small.”) case 10…99: print(“a is medium.”) case 100…199: print(“a is big.”) default: print(“a is not sure.”) }

// DISPLAY: // a is big.


###### Tuples

swift let cs = (1, 1) switch cs { case (0, 0): print(“(0, 0) is center.”) case (_, 0): print(“((cs.0), 0)“) case (0, _): print(“(0, (cs.1))“) case (-2…2, -2…2): print(“((cs.0), (cs.1)) is inside.“) default: print(“((cs.0), (cs.1)) is not sure.“) }

// DISPLAY: // (1, 1) is inside.


###### Value Bindings

swift let cs = (2, 1) switch cs { case (let x, 0): print(”(x)“) case (0, let y): print(”(y)“) case let (x, y): print(“((x), (y))“) }

// DISPLAY: // (2, 1)


###### Where

swift let cs = (1, -1) switch cs { case let (x, y) where x == y: print(“((x), (y)) x == y”) case let (x, y) where x == -y: print(“((x), (y)) x == -y”) case let (x, y): print(“((x), (y))“) }

// DISPLAY: // (1, -1) x == -y


#### Control Transfer Statements

##### Continue & Break

Like C, omitted.

##### Fallthrough

Like C.

swift let i = 5 var d = “The number (i) is” switch i { case 2, 3, 5, 7, 11, 13, 17, 19: d += “ a prime number, and also” fallthrough default: d += “ an integer.” } print(d)

// DISPLAY: // The number 5 is a prime number, and also an integer.


##### Labeled Statements

`label name: while condition { statements }` in `switch` & `while`

#### Early Exit

swift func test() { let d = [“hello”: “hi”] guard d.isEmpty else { print(“c isn’t empty.”) return } } test()

// DISPLAY: // c isn’t empty.


#### Checking API Availability

![3]()

swift if #available(iOS 9, *) { print(“Yes”) } else { print(“No”) }

// DISPLAY: // Yes


---

### Collection Types

![1]()

Swift provides three primary *collection types*, known as arrays, sets, and dictionaries, for storing collections of values.
1. Arrays are ordered collections of values. 
2. Sets are unordered collections of unique values. 
3. Dictionaries are unordered collections of key-value associations.

Arrays, sets, and dictionaries in Swift are always clear about the types of values and keys that they can store. This means that you cannot insert a value of the wrong type into a collection by mistake. It also means you can be confident about the type of values you will retrieve from a collection.

Swift’s array, set, and dictionary types are implemented as *generic(`adj.范型`) collections*. 

#### Mutability(`n.易变性`) of Collections

If you create an array, a set, or a dictionary, and assign it to a variable, the collection that is created will be *mutable*. This means that you can change (or *mutate*) the collection after it is created by adding, removing, or changing items in the collection. If you assign an array, a set, or a dictionary to a constant, that collection is immutable, and its size and contents cannot be changed.

It is good practice to create immutable collections in all cases where the collection does not need to change. Doing so enables the Swift compiler to optimize the performance of the collections you create.

#### Arrays

Swift’s `Array` type is bridged to Foundation’s `NSArray` class.

##### Array Type Shorthand(`n.速记`) Syntax

`Array<Element>` & `[Element]`

##### Creating an Empty Array

swift var a = [Int]() print(a.count)

a.append(3) print(a) a = [] print(a,count)

// DISPLAY: // 0 // [3] // 0


##### Creating an Array with a Default Value

swift var a = Double print(a)

// DISPLAY: // [0.0, 0.0, 0.0]


##### Creating an Array by Adding Two Arrays Together

swift var a = Double var b = Double var c = b + a print©

// DISPLAY: // [1.5, 1.5, 0.0, 0.0, 0.0]


##### Creating an Array with an Array Literal

swift var s: [String] = [“mai”, “mieng”] var str = [“mai”, “mieng”] if s == str { print(“s == str”) }

// DISPLAY: // s == str


##### Accessing and Modifying an Array

swift var s: [String] = [“mai”, “mieng”]

print(s.count) print(s.isEmpty)

s.append(“.com”) s += [“v2ex”, “.com”]

s[3] = “sspai” print(s[3])

s[3…4] = [] print(s)

s.insert(“http://“, atIndex: 0) print(s)

print(s.removeAtIndex(0)) print(s.removeLast())

print(s)

// DISPLAY: // 2 // false // sspai // [“mai”, “mieng”, “.com”] // [“http://“, “mai”, “mieng”, “.com”] // http:// // .com // [“mai”, “mieng”]


##### Iterating(`v.重复`) Over an Array

swift var s: [String] = [“mai”, “mieng”]

for str in s { print(str) }

for (index, value) in s.enumerate() { print(“((index), (value))“) }

// DISPLAY: // mai // mieng // (0, mai) // (1, mieng)


#### Sets

A *set* stores distinct values of the same type in a collection with no defined ordering. You can use a set instead of an array when the order of items is not important, or when you need to ensure that an item only appears once.

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

##### Hash Values for Set Types

Omitted.

##### Set Type Syntax

`Set<Element>`

##### Creating and Initializing an Empty Set

swift var s = Set() print(s.count)

s.insert(“!”) print(s.count)

s = [] print(s.count)

// DISPLAY: // 0 // 1 // 0


##### Creating a Set with an Array Literal

swift var s: Set = [1, 2, 3, 4] var set: Set = [“mai”, “mieng”]


##### Accessing and Modifying a Set

swift var s: Set = [1, 2, 3, 4] print(s.count)

if !s.isEmpty { print(“s is empty.”); }

s.insert(5) print(s.count)

print(s.remove(3))

print(s.remove(3))

s.removeAll() print(s.count)

if s.contains(3) { print(“s contains 3.”) } else { print(“s doesn’t contain 3.”) }

// DISPLAY: // 4 // s is empty. // 5 // Optional(3) // nil // 0 // s doesn’t contain 3


##### Iterating Over a Set

swift var s: Set = [1, 2, 3, 4]

for set in s { print(”(set)“) }

for set in s.sort() { print(”(set)“) }

// DISPLAY: // 2 // 3 // 1 // 4 // 1 // 2 // 3 // 4


#### Performing Set Operations

##### Fundamental Set Operations

![2]()

swift var a: Set = [1, 2, 3, 4, 5] var b: Set = [2, 4, 6] var c: Set = [1, 3, 5]

print(a.exclusiveOr(b).sort()) print(a.intersect©.sort()) print(b.union©.sort())

print(a.subtract(b).sort()) print(b.subtract(a).sort())

// DISPLAY: // [1, 3, 5, 6] // [1, 3, 5] // [1, 2, 3, 4, 5, 6] // [1, 3, 5] // [6]


##### Set Membership and Equality

swift var a: Set = [“😂”, “😊”] var b: Set = [“😊”, “😄”] var c: Set = [“😂”]

print(a == b) print(c.isSubsetOf(a)) print(a.isSupersetOf(a))

print(c.isDisjointWith(b)) print(c.isStrictSubsetOf(a)) print(a.isStrictSubsetOf(a))

print(a.isStrictSupersetOf©) print(a.isStrictSupersetOf(a))

// DISPLAY: // false // true // true // true // true // false // true // false


#### Dictionaries

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

##### Dictionary Type Shorthand Syntax

`Dictionary<Key, Value>` & `[Key: Value]`

##### Creating an Empty Dictionary

swift var d = [Int: String]()

d[404] = “not found” print(d.count)

d = [:] print(d.count)

// DISPLAY: // 1 // 0


##### Creating a Dictionary with a Dictionary Literal

swift var d: [Int: String] = [404: “not found”, 502: “bad gateway”] var dy = [“height”: 180, “weight”: 60]


##### Accessing and Modifying a Dictionary

swift var dy = [“height”: 180, “weight”: 60]

print(dy.count)

dy[“wage”] = 0 print(dy)

dy[“height”] = 185 print(dy)

print(dy.updateValue(65, forKey: “weight”))

dy[“wage”] = nil print(dy)

print(dy.removeValueForKey(“age”))

// DISPLAY: // 2 // [“height”: 180, “weight”: 60, “wage”: 0] // [“height”: 185, “weight”: 60, “wage”: 0] // Optional(60) // [“height”: 185, “weight”: 65] // nil


##### Iterating Over a Dictionary

To iterate over the keys or values of a dictionary in a specific order, use the `sort()` method on its `keys` or `values` property.

swift var dy = [“age”: 20, “height”: 180, “weight”: 60, “wage”: 0]

for (des, value) in dy { print(“(” + des + “, (value))“) }

for des in dy.keys { print(des) }

for value in dy.values { print(value) }

var dyDes = String var dyValue = Int

// DISPLAY: // (height, 180) // (age, 20) // (weight, 60) // (wage, 0) // height // age // weight // wage // 180 // 20 // 60 // 0

// — for d in dy.enumerate() { print(d) } // — // DISPLAY: // (0, (“height”, 180)) // (1, (“age”, 20)) // (2, (“weight”, 60)) // (3, (“wage”, 0))


---

### Strings and Characters

Swift’s `String` type is bridged with Foundation’s `NSString` class. If you are working with the Foundation framework in Cocoa, the entire `NSString` API is available to call on any `String` value you create when type cast to `NSString`, as described in AnyObject. You can also use a `String` value with any API that requires an `NSString` instance.

#### String Literals(`n.字面量`)

swift let testString = “maimieng”


#### Initializing an Empty String

swift var s = “” var str = String() s = “hello” if Str.isEmpty { Str = “hi” } print(s + “ ” + str)

var Str: String Str = “” // Initialize if Str.isEmpty { Str = “Hi!” } print(Str) // DISPLAY: // hello hi // Hi!


#### String Mutability(`n.易变性`)

swift var myWebsite = “maimieng” myWebsite += “.com”


#### Strings Are Value Types

Behind the scenes, Swift’s compiler optimizes(`v.优化`) string usage so that actual copying takes place only when absolutely necessary. This means you always get great performance when working with strings as value types.

#### Working with Characters

swift for c in “Laugh: 😂”.characters { print© } let testCharacter: Character = “.” var charArray: [Character] = [“s”, “w”, “i”, “f”, “t”] print(charArray) print(String(charArray)) // DISPLAY: // L // a // u // g // h // : //
// 😂 // [“s”, “w”, “i”, “f”, “t”] // swift


#### Concatenating(`n.连接`) Strings and Characters

You can’t append a `String` or `Character` to an existing `Character` variable, because a `Character` value must contain a single character only.

swift var a = “mai” var b = “mieng” var c: Character = “.” var d = a + b a += b d.append© print(a) print(d) // DISPLAY: // maimieng // maimieng.


#### String Interpolation(`n.插入`)

The expressions you write inside parentheses(`n.圆括号`) within an interpolated(`adj.插入的`) string cannot contain an unescaped double quote (`"`) or backslash (`\`), and cannot contain a *carriage return(`回车`)* or *line feed(`换行`)*.

swift let multiplier = 3 let message = “(multiplier) times 2.5 is (Double(multiplier) * 2.5)” print(message) // DISPLAY: // 3 times 2.5 is 7.5


#### Unicode

Swift’s `String` and `Character` types are fully Unicode-compliant, as described in this section.

##### Unicode Scalars(`n.标量`)

Behind the scenes, Swift’s native `String` type is built from Unicode scalar values. A Unicode scalar is a unique(`adj.唯一的`) 21-bit number for a character or modifier(`n.修饰符`), such as `U+0061` for `LATIN(adj.拉丁的) SMALL LETTER A` (`"a"`), or `U+1F425` for `FRONT-FACING BABY CHICK` (`"🐥"`).

> NOTE
A Unicode scalar is any Unicode code point in the range `U+0000` to `U+D7FF` inclusive(`adj.包括的`) or `U+E000` to `U+10FFFF` inclusive. Unicode scalars do **not** include the Unicode surrogate(`n.替代品`) pair code points, which are the code points in the range `U+D800` to `U+DFFF` inclusive.

Note that **not** all 21-bit Unicode scalars are assigned to a character—some scalars are reserved for future assignment. Scalars that have been assigned to a character typically also have a name, such as `LATIN SMALL LETTER A` and `FRONT-FACING BABY CHICK` in the examples above.

##### Special Characters in String Literals

String literals can include the following special characters:
- The escaped special characters `\0` (null character), `\\` (backslash), `\t` (horizontal(`adj.水平的`) tab), `\n` (line feed), `\r` (carriage return), `\"` (double quote) and `\'` (single quote)
- An arbitrary(`adj.武断的`) Unicode scalar, written as `\u{n}`, where `n` is a 1–8 digit hexadecimal number with a value equal to a valid Unicode code point

The code below shows four examples of these special characters. The `wiseWords` constant contains two escaped double quote characters. The `dollarSign`, `blackHeart`, and `sparklingHeart` constants demonstrate the Unicode scalar format:

swift let wiseWords = “\“Imagination is more important than knowledge\” - Einstein” let dollarSign = “\u{24}” let blackHeart = “\u{2665}” let sparklingHeart = “\u{1F496}” print(wiseWords) print(dollarSign) print(blackHeart) print(sparklingHeart) // DISPLAY: // “Imagination is more important than knowledge” - Einstein // $ // ♥ // 💖


##### Extended Grapheme(`n.字形`) Clusters(`n.群集`)

Every instance of Swift’s `Character` type represents a single extended grapheme cluster. An extended grapheme cluster is a sequence of one or more Unicode scalars that (when combined) produce a single human-readable character.

Here’s an example. The letter `é` can be represented as the single Unicode scalar `é` (`LATIN SMALL LETTER E WITH ACUTE(n.重读)`, or `U+00E9`). However, the same letter can also be represented as a pair of scalars—a standard letter `e` (`LATIN SMALL LETTER E`, or `U+0065`), followed by the `COMBINING ACUTE ACCENT` scalar (`U+0301`). The `COMBINING ACUTE ACCENT` scalar is graphically applied to the scalar that precedes(`v.优先`) it, turning an `e` into an `é` when it is rendered(`v.成为`) by a Unicode-aware text-rendering system.

In both cases, the letter `é` is represented as a single Swift Character value that represents an extended grapheme cluster. In the first case, the cluster contains a single scalar; in the second case, it is a cluster of two scalars:

swift let eAcute: Character = “\u{E9}” let combinedEAcute: Character = “\u{65}\u{301}” print(eAcute) print(combinedEAcute) // DISPLAY: // é // é


Extended grapheme clusters are a flexible way to represent many complex script characters as a single Character value. For example, Hangul(`n.韩语`) syllables(`n.音节`) from the Korean alphabet can be represented as either a precomposed(`adj.预先构成的`) or decomposed(`adj.已分解的`) sequence. Both of these representations qualify as a single Character value in Swift:

swift let precomposed: Character = “\u{D55C}” let decomposed: Character = “\u{1112}\u{1161}\u{11AB}” print(precomposed) print(decomposed) // DISPLAY: // 한 // 한


Extended grapheme clusters enable scalars for enclosing marks (such as `COMBINING ENCLOSING CIRCLE`, or `U+20DD`) to enclose other Unicode scalars as part of a single Character value:

swift let enclosedEAcute: Character = “\u{E9}\u{20DD}” print(enclosedEAcute) // DISPLAY: // é⃝


Unicode scalars for regional indicator symbols can be combined in pairs to make a single `Character` value, such as this combination of `REGIONAL INDICATOR SYMBOL LETTER U` (`U+1F1FA`) and `REGIONAL INDICATOR SYMBOL LETTER S` (`U+1F1F8`):

swift let regionalIndicatorForUS: Character = “\u{1F1FA}\u{1F1F8}” print(regionalIndicatorForUS) // DISPLAY: // 🇺🇸


#### Counting Characters

Note that Swift’s use of extended grapheme clusters for `Character` values means that string concatenation and modification may not always affect a string’s character count.

> NOTE
Extended grapheme clusters can be composed of one or more Unicode scalars. This means that different characters—and different representations of the same character—can require different amounts of memory to store. Because of this, characters in Swift do not each take up the same amount of memory within a string’s representation. As a result, the number of characters in a string cannot be calculated without iterating(`v.遍历`) through the string to determine its extended grapheme cluster boundaries. If you are working with particularly long string values, be aware that the `characters` property must iterate over the Unicode scalars in the entire string in order to determine the characters for that string.

> The count of the characters returned by the `characters` property is not always the same as the length property of an `NSString` that contains the same characters. The length of an `NSString` is based on the number of 16-bit code units within the string’s UTF-16 representation and not the number of Unicode extended grapheme clusters within the string.

swift let myWebsite = “我的网址是:maimieng.com 😂” print(myWebsite.characters.count) // DISPLAY: // 20

var enclosedEAcute = “\u{E9}” print(enclosedEAcute.characters.count) enclosedEAcute += “\u{20DD}” print(enclosedEAcute.characters.count) // DISPLAY: // 1 // 1


#### Accessing and Modifying a String

##### String Indices(`n.索引`)

swift let myWebsite = “maimieng.com” print(myWebsite[myWebsite.startIndex]) print(myWebsite[myWebsite.endIndex.predecessor()]) print(myWebsite[myWebsite.startIndex.successor()])

var index = myWebsite.startIndex.advancedBy(8) print(myWebsite[index])

for index in myWebsite.characters.indices { print(”(myWebsite[index])“, terminator: “_“) }

// DISPLAY: // m // m // a // . // m_a_i_m_i_e_ng._c_om

// INCORRECT CODE: // print(myWebsite[myWebsite.endIndex - 1]) // The ‘endIndex’ isn’t type ‘int’ but ‘index’. // print(myWebsite[myWebsite.endIndex]) // print(myWebsite[myWebsite.startIndex.predecessor()]) // Runtime error: Beyond the string’s range.


##### Inserting and Removing

swift var myWebsite = “maimiengcom” myWebsite.insert(“.”, atIndex: myWebsite.startIndex.advancedBy(8)) print(myWebsite)

myWebsite.insertContentsOf(“http://“.characters, at: myWebsite.startIndex) print(myWebsite)

myWebsite.removeAtIndex(myWebsite.endIndex.advancedBy(-4)) print(myWebsite)

let range = myWebsite.endIndex.advancedBy(-3)..<myWebsite.endIndex myWebsite.removeRange(range) print(myWebsite)

// DISPLAY: // maimieng.com // http://maimieng.com // http://maimiengcom // http://maimieng


#### Comparing Strings

##### String and Character Equality

String and character comparisons in Swift are *not* locale-sensitive(`adj.本地敏感的`).(意思是 Swift 中的字符和字符串无论在哪个语言区域,其表现和功能都是相同的)

`==` & `!=`:

swift var a = “hello” var b = “hello”

if a == b { print(“a == b”) } // DISPLAY: // a == b


Two `String` values (or two Character values) are considered equal if their extended grapheme clusters are *canonically(`adv.按标准地`) equivalent*. Extended grapheme clusters are canonically equivalent if they have the same linguistic(`adj.语言学的`) meaning and appearance, even if they are composed from different Unicode scalars behind the scenes.

For example, `LATIN SMALL LETTER E WITH ACUTE` (`U+00E9`) is canonically equivalent to `LATIN SMALL LETTER E` (`U+0065`) followed by `COMBINING ACUTE ACCENT` (`U+0301`). Both of these extended grapheme clusters are valid ways to represent the character `é`, and so they are considered to be canonically equivalent:

swift let eAcuteQuestion = “\u{E9}”

let combinedEAcuteQuestion = “\u{65}\u{301}”

if eAcuteQuestion == combinedEAcuteQuestion { print(eAcuteQuestion + “ == ” + combinedEAcuteQuestion) } // DISPLAY: // é == é


Conversely, `LATIN CAPITAL LETTER A` (`U+0041`, or `"A"`), as used in English, is *not* equivalent to `CYRILLIC CAPITAL LETTER A` (`U+0410`, or `"А"`), as used in Russian. The characters are visually similar, but do not have the same linguistic meaning:

swift let latinCapitalLetterA:Character = “\u{41}”

let cyrillicCapitalLetterA:Character = “\u{0410}”

if latinCapitalLetterA != cyrillicCapitalLetterA { var a = “”, b = “” a.append(cyrillicCapitalLetterA) b.append(latinCapitalLetterA) print(a + “ != ” + b) } // DISPLAY: // А != A


##### Prefix and Suffix Equality

The `hasPrefix(_:)` and `hasSuffix(_:)` methods perform a character-by-character canonical equivalence comparison between the extended grapheme clusters in each string.

swift let iPhone = [ “2007: iPhone”, “2008: iPhone 3G”, “2009: iPhone 3GS”, “2010: iPhone 4”, “2011: iPhone 4s”, “2012: iPhone 5”, “2013: iPhone 5c”, “2013: iPhone 5s”, “2014: iPhone 6”, “2014: iPhone 6 Plus”, “2015: iPhone 6s”, “2015: iPhone 6s Plus” ]

var hasC = 0 var in2015 = 0 for i in iPhone { if i.hasSuffix(“c”) { hasC++ } if i.hasPrefix(“2015”) { in2015++ } } print(hasC) print(in2015)

// DISPLAY: // 1 // 2


#### Unicode Representations of Strings

Omitted.

---

### Basic Operators

#### Terminology(`n.术语`)


Unary(`adj.一元的`), binary(`adj.二元的`), or ternary(`adj.三元的`) operators.

swift int a = 10 int b = -a

a ? b : c


#### Assignment Operator

Assignment operator does **not return** a value.

swift let a = 10 var v = 5 v = a

let (x, y) = (1, 2) print(“((x), (y))“) // DISPLAY: // (1, 2)

// if (x = y) { // … // } // Bug: // x = y does not return a value.


#### Arithmetic(`n.算术`) Operators

swift let a = 1 let b = 5

var c: Int c = a + b print©

c = a - b print©

c = a * b print©

var d = Double(a) / Double(b) print(d) // DISPLAY: // 6 // -4 // 5 // 0.2


##### Remainder(`n.求余`) Operator

To determine the answer for `a % b`, the `%` operator calculates the following equation and returns remainder as its output:

`a = (b x some multiplier) + remainder`

swift var a = 2 var b = 5 var c = -4

print(a % b) print(c % b)

// DISPLAY: // 2 // -4


##### Floating-Point Remainder Calculations

swift var d = 0.3 var e = 0.8

print(e % d) // DISPLAY: // 0.2


##### Increment and Decrement Operators

swift var a = 1 print(a++) print(++a) // DISPLAY: // 1 // 3


##### Unary Minus Operator & Unary Plus Operator

swift var a = -1 a = -a print(a) print(+a) // DISPLAY: // 1 // 1


#### Compound(`adj.复合的`) Assignment Operators

swift print(1 == 5) print(1 != 5) print(1 >= 5) print(1 <= 5) print(2 > 3) print(2 < 3) // DISPLAY: // false // true // false // true // false // true


#### Ternary Conditional Operator

swift let a = true let b = a ? 1 : 0 print(b)

let c: Int if a { c = 1 } else { c = 0 } print© // DISPLAY: // 1 // 1


#### Nil Coalescing(`n.合并`) Operator

The `nil` coalescing operator (`a ?? b`) unwraps an optional `a` if it contains a value, or returns a default value `b` if a is `nil`. 

The expression `a` is always of an optional type.
The expression `b` must match the type that is stored inside `a`.

swift let defaultGreeting = “Hello!” var myGreeting: String? print(myGreeting ?? defaultGreeting) myGreeting = “Hi!” print(myGreeting ?? defaultGreeting) // DISPLAY: // Hello! // Hi!


#### Range Operators

##### Closed Range Operator & Half-Open Range Operator

`for-in` loop:

The closed range operator (`a...b`) defines `a` range that runs from `a` to `b`, and includes the values `a` and `b`.
The half-open range operator (`a..<b`) defines `a` range that runs from `a` to `b`, but does **not** include `b`. 

swift // 1…9 equals to 1..<10 for i in 1...9 { for j in 1...9 { if (i >= j) { print(”(j) * (i) = (i * j) “, terminator: “”) } } print(“”) } // DISPLAY: // 1 * 1 = 1 // 1 * 2 = 2 2 * 2 = 4 // 1 * 3 = 3 2 * 3 = 6 3 * 3 = 9 // 1 * 4 = 4 2 * 4 = 8 3 * 4 = 12 4 * 4 = 16 // 1 * 5 = 5 2 * 5 = 10 3 * 5 = 15 4 * 5 = 20 5 * 5 = 25 // 1 * 6 = 6 2 * 6 = 12 3 * 6 = 18 4 * 6 = 24 5 * 6 = 30 6 * 6 = 36 // 1 * 7 = 7 2 * 7 = 14 3 * 7 = 21 4 * 7 = 28 5 * 7 = 35 6 * 7 = 42 7 * 7 = 49 // 1 * 8 = 8 2 * 8 = 16 3 * 8 = 24 4 * 8 = 32 5 * 8 = 40 6 * 8 = 48 7 * 8 = 56 8 * 8 = 64 // 1 * 9 = 9 2 * 9 = 18 3 * 9 = 27 4 * 9 = 36 5 * 9 = 45 6 * 9 = 54 7 * 9 = 63 8 * 9 = 72 9 * 9 = 81


#### Logical Operators

##### Logical NOT Operator

swift let a = true if !a { print(“true”) } else { print(“false”) } // DISPLAY: // false


##### Logical AND Operator & Logical OR Operator

swift let a = true let b = false

if a && b { print(“true”) } else if (a || b) { print(“false”) } // DISPLAY: // false


##### Combining Logical Operators

The Swift logical operators `&&` and `||` are left-associative, meaning that compound expressions with multiple logical operators evaluate the leftmost subexpression first.

swift let a = true let b = !a // false let c = a && b // false let d = a || b // true if a && b || c && d { print(“true”) } else { print(“false”) } // DISPLAY: // false


##### Explicit(`adj.明确的`) Parentheses(`n.小括号`)

swift let a = true let b = !a // false let c = a && b // false let d = a || b // true if (a || b) && (c || d) { print(“true”) } else { print(“false”) } // DISPLAY: // true


---

### The Basics

#### Constants and Variables

##### Declaring Constants and Variables

swift var i = 3 var Pi = 3.14, c = “V”

let myWebsite = “maimieng.com”


##### Type Annotations

swift var sumOfStu: Int var newColor, silver, gold, space_gray: String newColor = “Rose Gold”


##### Naming Constants and Variables

swift let π = 3.14 let 😂 = “大笑” var 网站 = “maimieng”

网站 += “.com”

let let = 1

// INCORRECT CODE: // π = 3 // R: π is a constant that can’t change its value.


##### Printing Constants and Variables

swift var myMac = “MacBook Pro” let myMacSize = 13 print(myMac + “ (myMacSize)“) // DISPLAY: // MacBook Pro 13


#### Comments

swift // Comment of one line.

/* Comment around several lines. */


#### Semicolons

swift let Sem = “;”; print(Sem) // DISPLAY: // ;


#### Integers

##### Integer Bounds(`n.范围`)

swift let minValue = Int64.min let maxValue = UInt8.max


##### Int

On a 32-bit platform, `Int` is the same size as `Int32`.
On a 64-bit platform, `Int` is the same size as `Int64`.

##### UInt

On a 32-bit platform, `UInt` is the same size as `UInt32`.
On a 64-bit platform, `UInt` is the same size as `UInt64`.

*`Int` is preferred.*

#### Floating-Point Numbers

`Double` represents a 64-bit floating-point number.
`Float` represents a 32-bit floating-point number.

*`Double` is preferred.*

`Double` has a precision(`n.明确`) of at least **15** decimal digits.
`Float` can be as little as **6** decimal digits.

#### Type Safety and Type Inference

swift let myPi = 3 + 0.14 // myPi is a double value.


#### Numeric(`adj.数值型的`) Literals

A *decimal* number, with no prefix
A *binary* number, with a `0b` prefix
An *octal(`adj.八进制的`)* number, with a `0o` prefix
A *hexadecimal(`adj.十六进制的`)* number, with a `0x` prefix

swift var myAge = 20 var binaryAge = 0b10100 var octalAge = 0o24 var hexadecimalAge = 0x14

let velocityOfLight = 3e9 let testNum = 0xFp-2 // testNum = 3.75

var moreThanOneThousand = 001_000.102_4


#### Numeric Type Conversion

##### Integer Conversion

swift // INCORRECT CODE: // var tooBig: UInt8 = UInt8.max + 1 // R: Beyond the range of UInt8.

var a: Int16 = 250 var b: Int8 = -1 var c = a + Int16(b)

// INCORRECT CODE: // var d = a + b // R: a & b are not the same type. // var e = Int8(a) + b // R: It’s not safe to convert type from Int16 to Int8.


##### Integer and Floating-Point Conversion

swift var a = 0.5 var b = 2 var c = a + Double(b) // c’s value is 2.5. var d = Int(a) + b // d’s value is 2. var e = 2 + 0.5 // INCORRECT CODE: // var f = a + b // R: a & b are not the same type.


#### Type Aliases

swift typealias ElementType = Int var a: ElementType a = 5


#### Booleans

swift let iAmAGoodMan = true if iAmAGoodMan { print(“You, too.”) } else { print(“You’re wrong.”) } if 2 >= 1 { print(“We are good at math.”) } // INCORRECT CODE: // if 1 { // … // } // R: The boolean values are only “true” & “false”.


#### Tuples

swift let http404Error = (404, “Not Found”) let (statusCode, _) = http404Error var stuInfo = (stuNum: 1415925, stuName: “V”) print(http404Error.0) print(statusCode) print(“The status code is (statusCode).“) print(“The student number is (stuInfo.stuNum).“) // DISPLAY: // 404 // 404 // The status code is 404. // The student number is 1415925.


#### Optionals

##### `nil`(`n.无`)

swift var moneyOfMine: Int? = 500 moneyOfMine = nil


##### If Statements and Forced Unwrapping

We can access its underlying(`n.位于其下`) value by adding an exclamation(`n.感叹`) mark (`!`) to the end of the optional’s name. 

swift var mySaving: Int? = 1000 if mySaving != nil { print(“I still have ¥(mySaving!).“) } else { print(“My saving is nil.”) } // DISPLAY: // I still have ¥ 1000.


##### Optional Binding

swift let possibleNumber = “123” let impossibleNumber = “maimieng” if let actualNumber = Int(possibleNumber) { print(”(possibleNumber) has an integer value.“) } if let actualNumber = Int(impossibleNumber) { print(”(impossibleNumber) has an integer value.“) } else { print(”(impossibleNumber) could not be converted to an integer.“) } // DISPLAY: // 123 has an integer value. // maimieng could not be converted to an integer.

if let firstNumber = Int(“4”), secondNumber = Int(“42”) where firstNumber < secondNumber { print(”(firstNumber) < (secondNumber)“) } // DISPLAY: // 4 < 42


We can include multiple optional bindings in a single `if` statement and use a `where` clause(`n.分句`) to check for a Boolean condition.

##### Implicitly Unwrapped Optionals

swift let possibleString: String? = “An optional string.” let forcedString: String = possibleString!

let assumedString: String! = “An implicitly unwrapped optional string.” let implicitString: String = assumedString

if possibleString != nil { print(possibleString!) }

if assumedString != nil { print(assumedString) } // DISPLAY: // An optional string. // An implicitly unwrapped optional string.

if let definiteString = possibleString { print(definiteString) }

if let definiteString = assumedString { print(definiteString) } // DISPLAY: // An optional string. // An implicitly unwrapped optional string.


Do not use an implicitly(`adv.含蓄地`) unwrapped(`v.解包`) optional when there is a possibility of a variable becoming `nil` at a later point. Always use a normal optional type if you need to check for a `nil` value during the lifetime of a variable.

#### Error Handling

If no error is thrown(`v.抛出`), the `eatASandwich()` function is called. If an error is thrown and it matches the `Error.OutOfCleanDishes` case, then the `washDishes()` function will be called. If an error is thrown and it matches the `Error.MissingIngredients` case, then the `buyGroceries(_:)` function is called with the associated `[String]` value captured(`v.捕获`) by the `catch` pattern.

swift func makeASandwich() throws { // … }

do { try makeASandwich() eatASandwich() } catch Error.OutOfCleanDishes { washDishes() } catch Error.MissingIngredients(let ingredients) { buyGroceries(ingredients) } // This code is just an example.


A `do` statement creates a new containing scope, which allows errors to be propagated(`v.传送`) to one or more `catch` clauses.

#### Assertions(`n.断言`)

##### Debugging with Assertions

swift let myAge = -1 assert(myAge >= 0, “Age should be bigger t WRONG han 0.”) // Bug: // assertion failed: Age should be bigger than 0.: file /Users/MaiMieng/Documents/test1/main.swift, line 12 (lldb) ```

When to Use Assertions

An integer subscript(adj.下标的) index is passed to a custom subscript implementation, but the subscript index value could be too low or too high. A value is passed to a function, but an invalid value means that the function cannot fulfill(v.实现) its task. An optional value is currently nil, but a non-nil value is essential(adj.基本的) for subsequent(adj.随后的) code to execute(v.运行) successfully.