Swift3 指導手冊:基礎篇

TwilaFreese 7年前發布 | 6K 次閱讀 Swift Apple Swift開發

在 Swift 3 指導手冊中,我們將聚焦如何幫助初學者從一個完完全全的新手到基本掌握 Swift 。這里會使用 Swift 3 來教學。我們編寫這個指導的初衷是因為市面上的很多指導手冊都已過時了,因此它就不適合僅僅以“ Swift3 有哪些新功能”來行文。我們找了幾位有多門語言的編程經驗的人士,來教你 Swift 語言的獨特性以及如何用好它。

變量和常量

任何 Swift 中的變量要么不變的,要么是可變的。這句話可不要和 Int 、 Float 這些變量類型混淆。變量和常量僅僅是一種視角來描繪持有的值是可修改的(即可變性),亦或是不能修改的(即不可變性)。

要定義一個常量,使用 let 關鍵字。

舉例來說:

let name = "Jameson"

如果你想改變 name 的值,會發現沒有辦法做到,然后 Swift 在編譯時會拋出一個錯誤。

let name = "Jameson"
name = "Bob"
error: cannot assign to value: 'name' is a 'let' constant
name = "Bob"

要解決它,我們可以使用 var 關鍵字,來定義一個可以修改的變量:

var name = "Jameson"
name = "Bob"

這次代碼就不會報錯了。

一般來說,你應該默認去使用 let 關鍵字,除非知道需要使用到 var 關鍵字。這樣的方式將會從根本上增加代碼的安全性。如果當你定義了常量,之后要去修改它時,你會得到錯誤提示,可以到那個時候再決定是不是應該使用 var 關鍵字。或者如錯誤是給你的提示,應該重新去思考當前的邏輯流。一般來說,不可變性優于可變性,它可以幫助開發者少犯錯誤,并且更容易編寫代碼。

基礎類型

在 Swift 中,一個類型被聲明的寫法是通過聲明一個變量,然后緊跟一個冒號,然后是類型名稱。例如我們聲明一個整型,在 Swift 中類型是 Int ,那么你可以如下寫法:

let age: Int = 5

相似的,你可以聲明一個字符串類型:

let name: String = "Jameson"

Swift 支持類型推斷,可以不寫具體的類型信息。然后讓編譯器根據它的初始值來推斷它是什么類型的。

let age = 5
let name = "Jameson"

age 和 name 的類型仍然是 Int 和 String ,但是這次我們跳過了類型聲明,因為很顯然,5 是 Int 類型,而 "Jameson" 是一個字符串。

記住, let 關鍵字僅僅使值變得不可變。如果我們預測這個 age 的值是可變的,而 name 不是可變的,那么我們應該這么寫:

var age = 5
let name = "Jameson"

現在如果要更新 age 的值,可以這么做:

var age = 5
let name = "Jameson"
age = 25
print(age)
25

使用字符串

用 print 打印命令或者 String 的字符串總是很方便。例如,我想要打印一個包含變量 age 和變量 name 的語句,可以在兩個 String 變量之間用 + 操作符。

let age = "15"
let name = "Robb"

let sentence = name + " is " + age
print(sentence)
Robb is 15

改用另外一個方式來拼接 String ,可以不使用 + 操作符,而是在將每一個變量放進一組括號中,并在變量前使用 \ 反斜杠。

let sentence = "\(name) is \(age)"
print(sentence)
Robb is 15

現在也可以看到同樣的效果,但是它更容易閱讀和組合。

也許你注意到了, age 現在是一個 String 類型因為它現在是 "15" 而不是 15,沒有了引號。這是因為如果一個字符串和一個整型組合, Int 類型將不會自動轉型為 String 類型,這在組合前是非常重要的一步。

這樣的話,以下代碼會產生錯誤。

let age = 15
let name = "Robb"

let sentence = name + " is " + age
print(sentence)
Error: Binary operator '+' cannot be applied to operands of type 'String' and 'Int'

因此我們所要做的就是將 age 變成一個 String 類型的。可以通過強制轉型來做到,使用 String 的初始化方法,傳入一個 Int 類型的值作為參數值。

let age = 15
let name = "Robb"

let stringAge = String(age)

let sentence = name + " is " + stringAge
print(sentence)
Robb is 15

我們創建了一個新的變量叫做 stringAge 。然后使用了類型轉換,因為字符串插值操作會單獨的分析每一個表達式,同樣獲取到圓括號內的內容。

let age = 15
let name = "Robb"

let sentence = name + " is " + String(age)
print(sentence)
print("\(name) enjoys being \(String(age))")
Robb is 15
Robb enjoys being
15

可選類型

Swift 中有可選類型的概念。一個可選類型是一個可以為 nil 、 null 或者是沒有被設置值的變量。一般來說,你可以認為大部分其他編程語言的任何變量都是一個可選類型。一個變量的可選性通過在類型聲明時的類型名稱后面加上問號符號 ? 來聲明。 因此繼續上面的例子,我們知道 age 和 name 總是會被設置,于是我們也許該添加另外一個可能為 nil 的變量。我們來拿 favoriteColor 來做一個例子。許多人都會有最愛的顏色,但可能對一部分人來說卻沒有,或者我們不知道別人的那些數據。因此我們會把它聲明為可選類型,并且不對它進行賦值。

var favoriteColor: String?

在對可選類型的聲明中如果不進行賦值,那么它就是 nil 的。你可以使用 print 函數來對它進行打印來證實這個觀點。

var favoriteColor: String?
print(favoriteColor)
nil

我們之后將對 favoriteColor 進行賦值,然后發現它不再是 nil 的。

var favoriteColor: String?
favoriteColor = "Blue"
print(favoriteColor)
Optional("Blue")

我們發現結果不是 "Blue" ,而是 Optional("Blue") 。那是因為實際值仍然包裹在可選類型之中。

你可以認為可選類型就像一個生日禮物,像禮物盒外面那層精美的包裝紙,拆開他們之后,也許里面什么都沒有。這對某些過生日的人真是個殘忍的禮物,不過這確實真的會發生。也許禮物盒中確實會有真的禮物,可也得拆開并且實際去看才知道,現在它只是一個沒有被拆開,躺在我們手中的一個盒子。

如果我們想知道里面是什么,需要馬上拆開禮物,對可選類型來說也是一樣,當傳遞和使用它們時,實際我們只是在和一個也許有值的容器在打交道。就像禮物一樣,可選類型在被使用之前必須被解包。

Swift 中聲明一個可選類型可以不賦值,編譯也會通過。但是如果我們聲明這些變量時不加上可選類型的符號,那么就會報錯。

var favoriteColor = "Blue"
favoriteColor = nil
error: nil cannot be assigned to type 'String'

同樣,非可選類型在聲明的時候也不能被賦值為 nil 。

var favoriteColor: String
error: variables must have an initial value

解包

我們現在知道可選類型是什么了,它們可以使變量可以為空,也知道與其說它們是值不如說是一個容器。因此,在項目中要訪問可選類型中的內容時,我們該怎么做?

第一,最普遍的方式是使用可選類型綁定,在可選綁定中,你可以在一個 if 語句中把可選類型的值賦給一個新的值。如果可選類型包含一個值,那個新的變量就會被成功設置,并且跟隨 if 語句的代碼閉包也會成功執行。

來看例子,這里將聲明兩個可選類型,一個叫做 favoriteAnimal ,它被設置值為 Fox ,而另外一個是 favoriteSong 我們并沒有對它進行賦值。

var favoriteAnimal: String?
var favoriteSong: String?

favoriteAnimal = "Fox"

現在我們使用可選綁定來看一看編程變量是否都有值,我們可以打印出包含它們值的語句。首先先來檢查一下 favoriteAnimal。

if let unwrappedFavoriteAnimal = favoriteAnimal {
    print("Favorite animal is: " + unwrappedFavoriteAnimal)
}
Favorite animal is: Fox

當沒有被設置值時,僅僅會觸發 else 語句,或者如果連 else 語句都沒有,那么什么都不會觸發。

if let unwrappedFavoriteSong = favoriteSong {
    print("Favorite song is: " + unwrappedFavoriteSong)
}
else {
    print("I don't know what your favorite song is!")
}
I don't know what your favorite song is!

如果我們要解包多個可選類型,并且對它們進行邏輯處理,首先要檢查它們:

var favoriteAnimal: String?
var favoriteSong: String?

favoriteAnimal = "Fox"
favoriteSong = "Shake it Off"

if let unwrappedFavoriteSong = favoriteSong {
    if let unwrappedFavoriteAnimal = favoriteAnimal {
        print(unwrappedFavoriteSong + " " + unwrappedFavoriteAnimal)
    }
}

這看上去非常雜亂,因此 Swift 提供一種簡便方式來一次解包多個變量:

var favoriteAnimal: String?
var favoriteSong: String?

favoriteAnimal = "Fox"
favoriteSong = "Shake it Off"

if let unwrappedFavoriteSong = favoriteSong,
    let unwrappedFavoriteAnimal = favoriteAnimal {
    print(unwrappedFavoriteSong + " " + unwrappedFavoriteAnimal)
}

集合類

Swift 有好幾種集合類型,最常用的是數組、集合、字典。

數組

我們首先來看一下數組的例子。

let starks: [String] = ["Eddard", "Catelyn", "Robb", "Sansa"]

這里我們定義了一個基本的 Array 類型,它是字符串數組類型 [String] 。

這個方括號暗示了它是一個存放字符串對象的數組,而不是一個字符串類型。一般來說,Swift 可以通過檢測所賦的初值進行類型推斷。

let starks = ["Robb", "Sansa", "Arya", "Jon"]

我們可以有多種方式訪問數組中的元素,比如通過 Int 類型的下標,或者調用各種集合類型的方法。

let starks = ["Robb", "Sansa", "Arya", "Jon"]
print( starks[0] )
print( starks[2] )
print( starks.first! )
Robb
Arya
Robb

你應該發現數組是以 0 為下標開始的,因此數組中的第一個元素 "Robb" 可以通過 stack[0] 來訪問。

另外,可能你會發現使用 first 方法返回的是一個可選值。而下標訪問器返回的并不是一個可選值。如果訪問數組中沒有出現的下標,程序將會在運行時報錯。因此在通過下標訪問時檢查數組的長度:

if starks.count >= 4 {
    print( starks[3] )
}

有幾種方式可以自動的檢查這個類型,但是因為一些性能原因它不會默認去做。

哈希類型/字典

字典可以存儲鍵值對,鍵的典型類型是字符串類型,但它也可以是 Swift 中的其他各種類型。在下面這個例子中,我們會創建一個基本字典,以字符串為鍵,整型為值。

let ages = ["Robb": 15, "Sansa": 12, "Arya": 10, "Jon": 15]

我們可以訪問這些值通過 String 的鍵

print( ages["Arya"]! )
print( ages["Jon"]! )
10
15

要注意的是,我們解包這些值只是因為它們是可選值,它們有可能為 nil

使用可選綁定來解包字典中的值是較安全的,特別是你認為這些值很有可能為 nil 時

if let aryasAge = ages["Arya"] {
    print("Arya is \(aryasAge) years old")
}
Arya is 10 years old

我們也可以把數組存儲在字典中,或者把字典存儲在數組中,或者把他們混合使用。

let families = [
    "Stark": ["Robb": 15, "Sansa": 12, "Arya": 10, "Jon": 15],
    "Baratheon": ["Joffrey": 13, "Tommen": 8]
]
let tommensAge = families["Baratheon"]!["Tommen"]!
print("Tommen is \(tommensAge) years old")
Tommen is 8 years old

這個 houses 的類型將會是 [String: [String: Int]]
另外一個角度也可以說,這是一個字符串為鍵,以 [String: Int] 為值的一個字典。

集合

Swift3 中的集合和數組很相似,但集合的值是唯一的和無序的。

初始化一個集合看起來就像初始化一個數組,唯一不同的是類型:

let colors: Set<String> = ["Blue", "Red", "Orange", "Blue"]

代碼創建了一個字符串的集合。大于和小于符號 "<"">" 暗示 Swift 中的泛型類型,你可能注意到了 "Blue" 在列表中出現了兩次,但是如果我們把顏色打印出來,馬上就會發現:

let colors: Set<String> = ["Blue", "Red", "Orange", "Blue"]
print(colors)

["Orange", "Red", "Blue"]

你也許還注意到了順序也不一致了,因為集合不會維持特定的順序。

我們無法像訪問數組下標一樣的方式去訪問集合。但是可以用集合中內置的方法來增加或者刪除元素,可以通過 contains 方法來查看是否集合中包含了該元素。

var colors: Set<String> = ["Blue", "Red", "Orange", "Blue"]
colors.insert("Black")
colors.insert("Black")
colors.remove("Red")
print(colors)
print(colors.contains("Black"))
print(colors.contains("Red"))


["Black", "Orange", "Blue"]
true
false

構造集合對象最常見的方式就是羅列哪些元素應該納入列表,哪些元素應該被排除。

這里還有許多方法我還沒有提到,我建議你去閱讀一下蘋果的官方文檔關于這三種集合類型,這樣就會對它們更了解。

元組

元組并不是一種集合,而應該說是用一個標識符來表示多個不同變量。

let fullName = ("Jameson", "Quave")

(String, String) 是一個元組類型,我們可以使用點語法來訪問每一個元組的成員,看看下面的情況:

let fullName = ("Jameson", "Quave")
print(fullName.1)
print(fullName.0)


Quave
Jameson

元組也可以用一個新的多個變量名來構造:

let (first, last) = ("Jameson", "Quave")
print(first)

Jameson

由于我們沒有用到 last name,可以忽略那個值通過使用下劃線 _ ,并且仍然構造 first name。

let (first, _) = ("Jameson", "Quave")
print(first)

Jameson

當你在使用方法時想返回多個返回值時,元組會很有用。

控制流

Swift 的控制流比起其他語言要優雅,我們先從 if 和 else 語句這些基本層面著手:

if 10 > 5 {
  print("10 is greater than 5.")
}
else {
    print("10 is not greater than five.")
}


10 is greater than 5

你也可以用括號來包裹 if 語句的條件:

if (10 > 5) {
...

Swift 也支持 switch 語句,在編譯期的時候檢查你是否已經覆蓋了所有的可能條件,如果你沒有覆蓋所有的條件,你得加上 defualt:case 來處理一些沒有考慮到的情況:

let name = "Jameson"
switch(name) {
case "Joe":
  print("Name is Joe")
case "Jameson":
  print("This is Jameson")
default:
  print("I don't know of this person!")
}

This is Jameson

由于此處 name 的值是 "This is Jameson" 。我們匹配到了第二個條件,然后執行下面這行。

print("This is Jameson")

如果我們把名稱設置為一些之前沒有出現在列舉情況的東西時,比如 "Jason" , switch 將會自動落入默認的情況:

let name = "Jason"
switch(name) {
case "Joe":
  print("Name is Joe")
case "Jameson":
  print("This is Jameson")
default:
  print("I don't know of this person!")
}

I don't know of this person!

循環和集合類型

Swift3 不再支持你過去所使用的 C 風格的循環,取而代之的是使用枚舉和 for-each 風格的循環,語法是 for element in array

let names = ["Robb", "Sansa", "Arya", "Jon"]

for name in names {
    print("Name: \(name)")
}

Name: Robb
Name: Sansa
Name: Arya
Name: Jon

如果你想要循環整個數組,這個寫法就很棒,沒有 C 風格的數組,如果我們循環遍歷一系列數字呢?Swift 中的 Range 和 Stride 給出了答案,如果想要打印到 10 里面3的倍數,可以使用 Range 通過使用語法 1...10 表示從 1 到 10 。然后我們打印每一個數字,那些數字都被 % 符號除以 3 ,并且檢查它們的余數是不是都是0。

for i in 1...10 {
    if i % 3 == 0 {
        print(i)
    }
}

3
6
9

另外一種方式是通過 stride 每隔三個元素訪問一次。 stride 可以用很多方法來創建,但是最常見的是 stride(from: , to:, by:) , from value 就是跨步訪問的起初值,然后 by 是每隔多少跨步值才能訪問到 to 值。聽起來有點繞,讓我們來看實際的代碼:

let byThrees = stride(from: 3, to: 10, by: 3)
for n in byThrees {
    print(n)
}

3
6
9

從英語來看十分好讀,你也可以說你從 3 數到 10 每隔3個數。這里我們創造 stride 并且用一個變量 byThrees 來存儲他們的值,但是也可以直接在循環中使用它們。

for n in stride(from: 3, to: 10, by: 3) {
    print(n)
}

3
6
9

集合都有一個 indices 屬性用于循環中使用,它會返回一個集合的下標數組,非常適合訪問或者過濾集合中某些元素的情況。這里回到我們的名稱集合的例子,如果想要前三個名稱,可以這樣寫:

let names = ["Robb", "Sansa", "Arya", "Jon"]
for nameIndex in names.indices {
    if(nameIndex < 3) {
        print(names[nameIndex])
    }
}

Robb, Sansa, Arya

在集合中還有枚舉的方法,它允許你通過遍歷下標和值:

let names = ["Robb", "Sansa", "Arya", "Jon"]
for (index, name) in names.enumerated() {
    print("\(index): \(name)")
}

0: Robb
1: Sansa
2: Arya
3: Jon

在 Swift3 中還有很多方式來遍歷對象,但他們通常不是很常用。

也許你已經發現我們的循環中同時給兩個變量賦值,index 和 name。它們被用逗號分隔并被括號括起來,表示我們從 enumerated() 返回的兩個被命名的變量。

本篇文章快速總結了一下 Swift 3 中手冊中比較基礎的部分,下一章,我將帶領你們在真是項目中去演練我們所學到的知識,做到活學活用。

 

來自:https://segmentfault.com/a/1190000008087979

 

 本文由用戶 TwilaFreese 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!