# A Quick Start Of Swift
<h2 id="0"></h2>
* [ 1. 學習目標](#1)
* [ 2. 基本類型](#2)
* [ 3. 控制流](#3)
* [ 4. 函數和方法](#4)
* [ 5. 類和初始化器](#5)
* [ 6. 枚舉和結構體](#6)
* [ 7. Swift 和 Cocoa Touch](#7)
* [ 8. 附錄](#8)
<br>
<h2 id="1">1. 學習目標</h2>
在本課程結束后,你將能夠:
+ 定義常量和變量,及其區別;
+ 了解隱式類型定義的使用和何時使用顯示類型定義。
+ 了解可選項的優點以及可選項綁定
+ 了解可選項以及隱式解包可選項的區別
+ 了解條件語句以及循環的功能
+ 了解函數、方法以及初始化器的區別
+ 了解類、結構體以及枚舉的區別
+ UIKit的導入和使用
+ 創建一個iOS App:魔法水晶球
<br>
[返回目錄](#0)
<br>
<h2 id="2">2. 基本類型</h2>
**常量**
在為其賦值之后值不能再次改變。常量的值在編譯時并不要求已知,但是你必須為其賦值一次。
```
let name:String = "OceanHorn"
print(name)
let language:String
language = "Swift"
```
> 一個扔掉鑰匙的透明保險箱,你知道里面有什么卻不能改變里面的東西。
>
> 一個沙漏,看得見里面的沙子,卻不能改變沙漏的計時長度。
>
> 一件過去發生的事,還是接受結果,活在當下吧。
**變量**
如其名,在定義之后可以改變其值,但是不能改變其類型。
```
var age:Int = 18
print(age)
age = 19
age = 20
age = "一朵花" // 會報錯
```
對于常量和變量,在聲明的時候直接給它們賦值就可以讓編譯器推斷它們的類型,就可以省略其類型(**類型推斷**)。比如:
```
let lastName = "Guo"
print(lastName)
var weight = 160
weight += 3 // 每逢佳節胖三斤
print(weight)
```
如果給出的信息不夠還是需要指明其類型,比如:
```
let explicitDouble: Double = 70
```
常量與變量名不能包含數學符號,箭頭,保留的(或者非法的)Unicode 碼位,連線與制表符。也不能以數字開頭,但是可以在常量與變量名的其他地方包含數字。
一旦你將常量或者變量聲明為確定的類型,你就不能使用相同的名字再次進行聲明,或者改變其存儲的值的類型。同時,你也不能將常量與變量進行互轉。
**類型轉換**
值永遠不會隱式地轉換為其他類型。如果你需要將一個值轉換為不同的類型,需要使用對應的類型顯示地聲明。
```
let label = "The width is "
let width = 94
let widthLabel = label + String(width)
print(widthLabel)
```
**字符串插值**
還有一種更簡單的方法來把值加入字符串:將值寫在圓括號里,然后再在圓括號的前邊寫一個反斜杠 (`\`) ,舉個例子:
```
let apples = 3
let oranges = 5
let appleSummary = "I have \(apples) apples."
let fruitSummary = "I have \(apples + oranges) pieces of fruit."
```
**可選類型**
可以利用可選類型來處理值可能缺失的情況。可選類型意味著:
+ 這里有一個值,他等于x
或者
+ 這里根本沒有值
在定義一個值得時候在其類型后面加一個(`?`)就可以將其定義為一個可選類型。
```
let optionalInt: Int? = 9
print(optionalInt)
```
一旦你**確定可選類型中包含值**,你可以在可選的名字后面加一個感嘆號 ( `!` ) 來獲取值,感嘆號的意思就是說“我知道這個可選類型里邊有值,展開吧。”這就是所謂的可選類型的強制展開。
```
let actualInt: Int = optionalInt!
print(actualInt) // 注意比較與之前打印的區別
if optionalInt != nil {
print("convertedNumber has an integer value of \(optionalInt!).")
}
```
可選類型在 Swift 中相當普遍,在值可能有也可能不存在的場景下非常有用。最典型的是在嘗試強制類型轉換的時候。
```
var myString = "7" // 嘗試把“7”改成“qi”
var possibleInt = Int(myString)
print(possibleInt)
```
**數組**
數組以有序的方式來儲存相同類型的值。相同類型的值可以在數組的不同地方多次出現。定義數組使用(`[]`),訪問數組成員可以用`[index]`,數組索引從0開始。
```
var ratingList = ["Poor", "Fine", "Good", "Excellent"]
ratingList[1] = "OK"
ratingList
```
創建一個空數組可以使用初始化器:
```
let emptyArray = [String]()
```
**隱式解析可選類型**
有時在一些程序結構中可選類型一旦被設定值之后,就會一直擁有值。在這種情況下,就可以去掉檢查的需求,也不必每次訪問的時候都進行展開,因為它可以安全的確認每次訪問的時候都有一個值。
隱式解析可選類型在故事版場景中很普遍,但是同樣可以像非可選類型那樣來使用,每次訪問的時候都不需要展開。下面的例子展示了在訪問被明確為 `String` 的可選類型展開值時,可選字符串和隱式解析可選類型字符串的行為區別:
```
let possibleString: String? = "An optional string."
let forcedString: String = possibleString! // requires an exclamation mark
let assumedString: String! = "An implicitly unwrapped optional string."
let implicitString: String = assumedString // no need for an exclamation mark
if assumedString != nil {
print(assumedString)
}
if let definiteString = assumedString {
print(definiteString)
}
```
在實際使用中很少需要自己創建隱式解析可選類型。通常情況下在代碼與故事版之間的接口中出現。
<br>
[返回目錄](#0)
<br>
<h2 id="3">3. 控制流</h2>
Swift 有兩種控制流語句。
+ 條件語句,像`if`, `switch`,判斷條件是否滿足,如果滿足(值為`true`)則執行滿足條件時的代碼
+ 循環語句,像`for-in`,`while`,來將一段代碼多次執行。
`if`可以與`else`語句配合,,用來在 `if` 條件為 `false` 的時候使用, 多個`if`語句可以進行多層嵌套。
```
let number = 23
if number < 10 {
print("The number is small")
} else if number > 100 {
print("The number is pretty big")
} else {
print("The number is between 10 and 100")
}
```
`for-in`語句與`if`語句也可以嵌套來實現更復雜的邏輯:
```
let individualScores = [75, 43, 103, 87, 12]
var teamScore = 0
for score in individualScores {
if score > 50 {
teamScore += 3
} else {
teamScore += 1
}
}
print(teamScore)
```
在`if`語句中使用**可選綁定**來檢查一個可選類型是否存在一個值:
```
var optionalName: String? = "John Smith" // 改為nil試試
var greeting = "Hello!"
if let name = optionalName {
greeting = "Hello, \(name)"
}
```
`where`語句也可以被添加到一個判斷case中來實現進一步的判斷,當所有條件都滿足的時候才會執行相關的代碼:
```
var optionalHello: String? = "Hello"
if let hello = optionalHello where hello.hasPrefix("H"), let name = optionalName {
greeting = "\(hello), \(name)"
}
```
可以用`Range`來創建一個索引范圍以便在循環中獲得索引,通過使用范圍運算符`..<`來創建索引范圍。
```
var firstForLoop = 0
for i in 0..<4 {
firstForLoop += i
}
print(firstForLoop)
```
`..<`創建的范圍不包括最后一個,如`0..<3`包含0,1,2 但不包含3。`...`創建的范圍包含最后一個索引。`0...3`包含0,1,2,3。
如果不關心索引,可以使用通配符`_`來替換索引:
```
var secondForLoop = 0
for _ in 0...4 {
secondForLoop += 1
}
print(secondForLoop)
```
<br>
[返回目錄](#0)
<br>
<h2 id="4">4. 函數和方法</h2>
函數是一個獨立的代碼塊,用來執行特定的任務。通過給函數一個名字來定義它的功能,并且在需要的時候,通過這個名字來“調用”函數執行它的任務。
使用`func`來定義一個函數。函數可以有0個到多個參數,用`name: Type`來表示。在調用函數時,需要為該函數的參數傳遞相應的值。函數可以沒有返回值,也可以有一個返回值,用`-> Type`表示。函數內部的具體實現在其后的`{}`中。
```
func greet(name: String, day: String) -> String {
return "Hello \(name), today is \(day)."
}
```
調用函數通過在函數名后的圓括號中相應的參數位值傳遞符合函數要求的值即可。通常情況下,對于第一個參數參數名是省略的,后面的參數前面會有對應的參數名。
```
greet("Anna", day: "Tuesday")
greet("Bob", day: "Friday")
greet("Charlie", day: "a nice day")
```
特定類型中定義的函數成為**方法**。方法被明確的關聯到它所定義的類型中,僅能夠被該類 或該類的實例調用。
```
let exampleString = "hello"
if exampleString.hasSuffix("lo") {
print("ends in lo")
}
```
像上面的那樣,可以使用點語法來調用方法。在調用時第一個參數忽略掉其參數名,后面的參數名都要加上。比如,下面的`Array`的方法有兩個參數,調用時僅需要
給出第二個參數名。(實際編寫代碼時都是自動提示的,僅需要傳遞參數值即可)
```
var array = ["apple", "banana", "dragonfruit"]
array.insert("cherry", atIndex: 2)
array
```
<br>
[返回目錄](#0)
<br>
<h2 id="5">5. 類和初始化器</h2>
面向對象編程中,編程的大量工作聚焦在對象間的交互上。對象是一個類的實例,
而類可以看成是對象的藍圖或者抽象。類中以屬性和方法的方式存儲了關于一系列對象共有的屬性及使用方法(行為)。
通過在`class`后面添加一個名稱來創建一個類。類中屬性的定義方法跟定義常量與變量的方法相同,類中方法的定義跟定義函數的方法也相同。
```
class Shape {
var numberOfSides = 0
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}
```
對于這個簡單的類,創建一個實例并調用其方法如下:
```
var shape = Shape()
shape.numberOfSides = 3
var shapeDescription = shape.simpleDescription()
```
`Shape`還少了一個重要的組成部分:一個初始化器。 **初始化器**用來為類、結構體或者枚舉完成準備實例的過程。涉及到為每個屬性設置一個初始化值,執行其他一些初始化操作等。使用`init`來創建初始化器。
```
class NamedShape {
var numberOfSides = 0
var name: String
init(name: String) {
self.name = name
}
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}
```
注意區分在初始化器中,是怎樣區分`name`屬性與`name`參數的。
需要特別提出的是:類中的每一個屬性都應該被賦值,要么通過定義時賦值,要么通過初始化器賦值。
對于`NamedShape`通過初始化器創建實例如下,在調用初始化器時需要包含所有的參數及其對應的變量名。
```
let namedShape = NamedShape(name: "my named shape")
```
<br>
[返回目錄](#0)
<br>
<h2 id="6">6. 枚舉和結構體</h2>
在 Swift 中,類不是創建數據類型的唯一途徑。 枚舉和結構體擁有跟類相似的能力, 而且在某些場景下更有效。
**枚舉**
枚舉為一組相關值定義了一個普通的類型,使得可以在編程時使用這些類型變得更加安全。枚舉也可以擁有與其值相關的方法。
使用`enum`來創建枚舉。
```
enum Rank: Int {
case Ace = 1
case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
case Jack, Queen, King
func simpleDescription() -> String {
switch self {
case .Ace:
return "ace"
case .Jack:
return "jack"
case .Queen:
return "queen"
case .King:
return "king"
default:
return String(self.rawValue)
}
}
}
let ace = Rank.Ace
let aceRawValue = ace.rawValue
```
在上面的例子中,枚舉的原始值類型是`Int`,所以你必須指定第一個枚舉項的原始值,其他項的原始值會自動順序加1。也可以使用字符串或者浮點數作為枚舉項的原始值。使用`rawValue`屬性來訪問枚舉項的原始值。
使用` init?(rawValue:)`初始化器來通過原始值創建對應枚舉類型的一個實例。
```
if let convertedRank = Rank(rawValue: 3) {
let threeDescription = convertedRank.simpleDescription()
}
```
枚舉成員的值都是自然值,不是他們原始值的另外一種表述方法。實際上,對于一個沒有意義的原始值,你是不需要提供的。
```
enum Suit {
case Spades, Hearts, Diamonds, Clubs
func simpleDescription() -> String {
switch self {
case .Spades:
return "spades"
case .Hearts:
return "hearts"
case .Diamonds:
return "diamonds"
case .Clubs:
return "clubs"
}
}
}
let hearts = Suit.Hearts
let heartsDescription = hearts.simpleDescription()
```
注意上面代碼中枚舉成員的兩種使用方法:
+ 定義常量`heart`時,類型尚不確定,后面需要使用`Suit.Hearts`為其賦值.
+ Suit內部,`switch self`(`switch`本課未講)時已經明確`self`為`Suit`類型,故可以直接使用縮寫的形式。
實際后面這樣也是可以的:
```
var someCase = Suit.Hearts
print(someCase.simpleDescription())
someCase = .Diamonds
let someDescription = someCase.simpleDescription()
```
**結構體**
使用`struct`來創建結構體。
```
struct Card {
var rank: Rank
var suit: Suit
func simpleDescription() -> String {
return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
}
}
let threeOfSpades = Card(rank: .Three, suit: .Spades)
let threeOfSpadesDescription = threeOfSpades.simpleDescription()
```
<br>
[返回目錄](#0)
<br>
<h2 id="7">7. Swift 和 Cocoa Touch</h2>
Swift 在設計時就考慮了與 Cocoa Touch 的無縫連接,以便將 Swift 用于 iOS App 的開發。
到目前為止我們使用的數據類型都來源于 Swift 的標準庫,比如 `String`,`Array` 等。 Swift 標準庫是為 Swift 設計的并嵌入其中,它有一系列的數據類型。
當編寫 iOS 應用時,你將使用除 Swift 標準庫之外更多的庫。其中一個在開發 App 時最常見的是 UIKit 。 UIKit 中包含了應用交互層相關的各種類。
導入 UIKit 的方式:
```
import UIKit
```
導入之后就可以使用 Swift 語法和 UIKit 中的各種類,來實現各種效果。
```
let redSquare = UIView(frame: CGRect(x: 0, y: 0, width: 44, height: 44))
redSquare.backgroundColor = UIColor.redColor()
```
<br>
[返回目錄](#0)
<h2 id="8">8. 附錄</h2>
[課程項目鏈接](https://git.oschina.net/OceanHorn/MagicCrystalBall)
[the-swift-programming-language-in-chinese
](https://github.com/numbbbbb/the-swift-programming-language-in-chinese)
[返回目錄](#0)