簡介
這是一個Swift語言教程,基于最新的iOS 9,Xcode 7.3和Swift 2.2,會為你介紹Swift編程非?;A的內容。從電腦如何工作的全程基本原理到語言結構,你會足夠了解這門語言,來處理數據和管理代碼的行為。
快速鏈接
- 一個下午讓你掌握Swift基礎 ( 1/9 ) 編程本質 & Playground基礎
- 一個下午讓你掌握Swift基礎 ( 2/9 ) 變量 & 常量
- 一個下午讓你掌握Swift基礎 ( 3/9 ) 數字類型 & 操作
- 一個下午讓你掌握Swift基礎 ( 4/9 ) 字符串
- 一個下午讓你掌握Swift基礎 ( 5/9 ) 做判斷
- 一個下午讓你掌握Swift基礎 ( 6/9 ) 重復步驟
- 一個下午讓你掌握Swift基礎 ( 7/9 ) 函數
- 一個下午讓你掌握Swift基礎 ( 8/9 ) 閉包
- 一個下午讓你掌握Swift基礎 ( 9/9 ) 可選值
- Swift 初學者 ( 10/12 ) 數組
- Swift 初學者 ( 11/12 ) 字典
- Swift 初學者 ( 12/12 ) 集合
做判斷
寫一個電腦程序的時候,需要能夠用不同的劇本告訴電腦該干什么。例如,一個計算器app在用戶按加號按鈕的時候要做一件事,按減號按鈕的時候做另一件事。
在電腦編程領域,這個概念被稱作控制流(control flow)。它被這樣命名因為程序的流程(flow)由多種方法控制。在這篇文章里,你會學習到在程序里如何做判斷,以及通過使用語法來控制流程。
if語句
第一個也是最常用的控制程序流程的方式就是使用if語句(if statement),可以讓程序只在某個特定情況是true的時候做一些事。例如,看下面的代碼:
if 2 > 1 {
print("是的,2比1大。")
}
這一個簡單的if語句。如果括號里的情況是true,語句就會執行花括號里的代碼。如果括號里的情況是false,語句不會執行花括號里的代碼。就這么簡單!
上面的代碼也為你介紹了新語法:print()函數,簡單地顯示一些東西到屏幕上。在你的playground里,你可以看見上面print()語句的結果,通過點擊 View\Debug Area\Show Debug Area。
你會看見這樣的東西:
點擊上面截圖上高亮的兩個按鈕也可以顯示debug(排除錯誤)區域。Xcode有很多方式來完成同樣的事情!
你可以擴展一個if語句,提供在情況是false的時候運行的代碼。這被稱作else子句(clause)。這是一個例子:
let animal = "狐貍"
if animal == "貓" || animal == "狗" {
print("這個動物是居家寵物。")
} else {
print("這個動物不是居家寵物。")
}
這里,如果(if)animal等于“貓”或“狗”,然后語句會運行代碼的第一塊。如果animal既不等于“貓”又不等于“狗”,語句會運行if語句里else里的那部分代碼,在debug區域顯示如下內容:
這個動物不是居家寵物。
其實使用 if 語句還能做更多事情。有時候你想檢測一個情況,然后是另一個情況。這就是else-if語句參演的地方啦。
你可以像這樣使用:
let hourOfDay = 12
let timeOfDay: String
if hourOfDay < 6 {
timeOfDay = "清晨"
} else if hourOfDay < 12 {
timeOfDay = "上午"
} else if hourOfDay < 17 {
timeOfDay = "下午"
} else if hourOfDay < 20 {
timeOfDay = "晚上"
} else if hourOfDay < 24 {
timeOfDay = "夜深了"
} else {
timeOfDay = "這他媽不是時間!"
}
print(timeOfDay)
一個接一個的else-if語句來測試多種情況,直到發現一個true情況。它只會執行和第一個true情況相關的代碼,無論隨后的else-if情況是不是true。換句話說,else-if情況的順序影響很大!
你可以在末尾加一個else,來處理所有都不是true的情況。else是可選的,如果你不需要它那就不要;在這個例子里你的確需要它,來確保timeOfDay在你輸出它的時候有一個有效值。
這個例子里,else-if語句帶有一個數字,表示一天中的時間,然后把它轉換到一個字符串,表示這個小時屬于一天中的哪個部分。采用24小時時間制,語句被按順序一個一個檢查:
- 第一次檢查看看小時是不是小于6。如果是,意味著在清晨。
- 如果小時不小于6,語句繼續執行第一個else-if,檢查小時是不是小于12。
- 然后按順序,在情況是false的時候,語句檢查小時是不是小于17,然后是小于20,然后是小于24。
- 最后,如果小時數超出范圍了,語句察覺到了一個無效情況,然后把這個信息打印到了控制臺。
在上面的代碼里,hourOfDay常量是12。因此,代碼會在屏幕上像下面這樣顯示:
下午
注意即使hourOfDay < 20和hourOfDay < 24情況也都是true,但語句只執行了輸入滿足的第一個else-if,當然就是hourOfDay < 17情況啦。
包含變量
If 語句介紹了一個新概念,那就是scope(范圍),通過使用花括號來包含變量的一種方式。
讓我們看一個例子。想象一下你要計算向顧客收取的費用。
這是你打好的算盤:
你每小時賺25塊,最多40小時,此后的每小時都要50塊。
使用Swift,你可以這樣計算你的費用:
var hoursWorked = 45
var price = 0
if hoursWorked > 40 {
let hoursOver40 = hoursWorked - 40
price += hoursOver40 * 50
hoursWorked -= hoursOver40
}
price += hoursWorked * 25
print(price)
這段代碼檢查小時數是不是超過40了。如果是,代碼計算超過40的小時數,然后用它乘上50塊,然后把結果加到價格上。代碼然后從工作的總時間里減去超過40小時的部分。把剩下的工作小時乘以25塊,然后加到總價上。
在上面的例子里,結果是這樣的:
1250
有意思的是 if 語句里面的代碼。有一個新常量的聲明,hoursOver40,來保存超過40小時的數字。
很明顯你可以在if語句里面使用它。但如果你嘗試在上面代碼的結尾去使用它,會發生什么?
···
print(price)
print(hoursOver40)
這會導致下面的錯誤:
`error: use of unresolved identifier 'hoursOver40'(錯誤:使用了不確定的標識符‘hoursOver40’)`
這個錯誤告訴你,你只被允許在創建 hoursOver40 常量的 scope 里使用它。這個例子里,if 語句引入了一個新 scope,所以當這個 scope 結束了,你就不能再使用這個常量了。
但是,每個 scope 可以使用來自它的父 scope 的變量和常量。在上面的例子里,if 語句里面的scope使用了 price 和 hoursWorked 變量,他們就是在父 scope 被創建的。
三目操作符(The ternary conditional operator)
現在我想介紹一個新的操作符,你在第三篇文章里沒有看到的。叫做三目操作符(The ternary conditional operator),它是和 if 語句相關的。
如果你想判斷兩個變量最小的值和最小的值,你可以像這樣使用if語句:
let a = 5
let b = 10
let min: Int
if a < b {
min = a
} else {
min = b
}
let max: Int
if a > b {
max = a
} else {
max = b
}
現在你知道這是怎么工作的了,但這有好多代碼。如果你能把它縮短到就幾行豈不是很好?唔,你可以的,感謝三目操作符!
三目操作符帶有一個情況,返回兩個值其中之一,取決于那個情況是true還是false。語法如下所示:
(<情況>) ? <TRUE值> : <FALSE值>
你可以使用這個操作符來重寫上面的長代碼塊,像這樣:
let a = 5
let b = 10
let min = a < b ? a : b
let max = a > b ? a : b
第一個例子里,情況是a<b。如果是true,賦值回min的結果會是a;如果是false,結果會是b的值。
我相信你也同意這樣簡單多了!這是一個有用的操作符,你會發現自己經常使用它。
**注意:**因為找兩個數字中更大的或更小的那個是如此常用的操作,Swift標準庫為這個目標提供了兩個函數:max和min。
迷你練習
創建一個叫做myAge的常量,初始化為你的年齡。寫一個if語句,如果你的年齡在13到19之間,就print“青少年”,如果不是,就print“不是青少年”。
Swift語句
控制流程的另一種方式是使用 switch 語句,允許你根據變量或常量的值來執行不同的代碼。
這是一個非常簡單的基于整數的 switch 語句:
let number = 10
switch (number) {
case 0:
print("零")
default:
print("非零")
}
這個例子,代碼會如下輸出:
非零
這個switch語句的作用是判斷數字是不是零。但它可以做更復雜一點的事!
要處理一個特殊情況,使用 case 后面跟著你想判斷的值,這個例子里是0。然后,用default來表明,如果是所有其它值應該做點什么。
這是另一個例子:
let number = 10
switch (number) {
case 10:
print("這是10!")
default:
break
}
這次你判斷10,在case里print了一條消息。如果是其他值,那什么都不應該發生。當你不想讓一個case或default發生任何事情的時候,那就用break關鍵字。這告訴Swift你不打算在這里寫任何代碼,任何事都不應該發生。
當然,switch語句也可以處理整數以外的數據類型。他們可以處理任何數據類型!這是一個基于string的例子:
let string = "狗"
switch (string) {
case "貓", "狗":
print("這個動物是居家型。")
default:
print("這個動物不是居家型。")
}
這會print如下內容:
這個動物是居家型。
這個例子里,你為case提供了兩個值,意味著如果值等于“貓”或“狗”,語句就會執行這個case。
你也可以給switch語句不止一個case。你在這篇文章之前的部分看見了一個 if 語句帶有 else-if 從句,可以把一天中的小時轉換為描述這是一天中的哪個部分的字符串。你可以用一個switch語句來更簡要的重寫它,像這樣:
let hourOfDay = 12
let timeOfDay: String
switch (hourOfDay) {
case 0, 1, 2, 3, 4, 5:
timeOfDay = "清晨"
case 6, 7, 8, 9, 10, 11:
timeOfDay = "上午"
case 12, 13, 14, 15, 16:
timeOfDay = "下午"
case 17, 18, 19:
timeOfDay = "晚上"
case 20, 21, 22, 23:
timeOfDay = "夜深了"
default:
timeOfDay = "這他媽不是時間!"
}
print(timeOfDay)
代碼會 print 如下內容:
下午
如果有多個case,語句會執行第一個滿足的case。你應該會同意這個例子比用if語句來的更簡要和清晰吧。細節上其實也更嚴謹,因為 if 語句沒法處理負數的情況,但這兒負數被正確地認為是無效的。
基于一個值的property來匹配一個case的情況也是可以的。就像你在第三篇學的,你可以使用模除操作符來判斷一個整數是偶數還是奇數。看看這段代碼:
let number = 10
switch (number) {
case let x where x % 2 == 0:
print("偶數")
default:
print("奇數")
}
這會print如下內容:
偶數
這個switch語句使用了let-where語法,意味著case只會在一個特定情況是true的時候匹配。這個例子里,你設計了case來滿足如果值是偶數的情況——那就是值模除2等于0啦。
這個可以基于情況來匹配值的方法叫做模式匹配(pattern matching)。
另一種方式使用switch語句也有絕佳效果,像這樣:
let coordinates: (x: Int, y: Int, z: Int) = (3, 2, 5)
switch (coordinates) {
case (0, 0, 0): // 1
print("原點")
case (_, 0, 0): // 2
print("在x軸上。")
case (0, _, 0): // 3
print("在y軸上。")
case (0, 0, _): // 4
print("在z軸上。")
default: // 5
print("空間里的某個位置")
}
這個switch語句利用了部分匹配(partial matching)。按順序說一下每個case都做了什么:
- 恰好匹配值是(0, 0, 0)的情況。這是3D空間的原點。
- 匹配y=0, z=0以及任意的x值。這意味著坐標點在x軸上。
- 匹配x=0, z=0以及任意的y值。這意味著坐標點在y軸上。
- 匹配x=0, y=0以及任意的z值。這意味著坐標點在z軸上。
- 匹配剩下的坐標。
用下劃線來表示你不在乎這個值。你早在第二篇文章就見過了,會并會在貫穿教程的多個地方看見它。因為這太好用了!
如果你不想忽略值,那你就能在switch語句里使用它,像這樣:
let coordinates: (x: Int, y: Int, z: Int) = (3, 2, 5)
switch (coordinates) {
case (0, 0, 0):
print("原點")
case (let x, 0, 0):
print("在x軸上 x = \(x)")
case (0, let y, 0):
print("在y軸上 y = \(y)")
case (0, 0, let z):
print("在z軸上 z = \(z)")
case (let x, let y, let z):
print("空間里的某個位置 x = \(x), y = \(y), z = \(z)")
}
這里坐標軸 case 使用 let 語法來把有關值取出。代碼然后使用字符串插入來構建一個字符串,把它 print 出來。
注意為什么這個switch語句不需要一個default。這是因為最后的case本質上就是default—它匹配任何值,因為對元組的任一部分都沒有限制。如果switch語句在cases里用光了所有可能的值,那就不需要什么default了。
最后,你也可以用與之前看到的同樣的let-where語法來匹配更復雜的情況。例如:
let coordinates: (x: Int, y: Int, z: Int) = (3, 2, 5)
switch (coordinates) {
case (let x, let y, _) where y == x:
print("在y = x線上。")
case (let x, let y, _) where y == x * x:
print("在y = x^2線上。")
default:
break
}
這里,你匹配了“y等于x”和“y等于x的平方”兩條線。
這些就是switch語句的基礎啦!
迷你練習
- 寫一個switch語句,基于一個整數的年齡,然后print出這個年齡對應的年齡層。你可以自己做一個年齡層,或者用我的分類方法:0-2歲:幼兒,3-12歲:兒童,13-19歲:青少年,20-39歲:成年人,40-60:中年人;61+:老人。
- 寫一個switch語句,基于包含了一個字符串和一個整數的元組。字符串是一個名字,整數是一個年齡。用和你在前一個練習同樣的情況,用 let 語法來 print 出名字接著年齡層。例如,我自己就應該 print 出“張嘉夫是一個成年人。”
關鍵點
- 用 if 語句做基于一個情況的簡單判斷。
- 在 if 語句里用 else 和 else-if 來為做判斷擴展,不止一個單獨的情況。
- 你可以在簡單 if 語句的地方用三目操作符。
- 變量和常量屬于一個特定的scope(范圍),越過了scope就不能再用他們了。一個scope可以繼承父scope的變量和常量。
- 用 switch 語句來基于一個變量或常量的值決定運行哪段代碼。
- switch 語句的強大來自于它使用模式匹配的能力,因為值可以用復雜規則來進行比較。
接下來去哪兒?
Apps很少全程時刻都運行在同樣的方式;根據來自網絡或用戶輸入的內容,你的代碼需要做判斷去哪條路。有了if,else和switch語句,你可以讓代碼基于一些情況來做決定。
和決定是否要做一些事相似,你也能決定做一些事多少次。在下一篇文章里,你會看到如何使用循環來多次重復步驟。
挑戰
挑戰A:你就是編譯器
下面的代碼哪里錯了?
let firstName = "嘉夫"
if firstName == "嘉夫" {
let lastName = "張"
} else if firstName == "陽" {
let lastName = "劉"
}
let fullName = lastName + firstName
挑戰B:結果預測
看看下面的switch語句:
switch (coordinates) {
case (let x, let y, let z) where x == y && y == z:
print("x = y = z")
case (_, _, 0):
print("在x/y平面上")
case (_, 0, _):
print("在x/z片面上")
case (0, _, _):
print("在y/z平面上")
default:
print("沒什么特別的")
}
在coordinates分別是下列每一個的時候,代碼會 print 什么?
let coordinates = (1, 5, 0)
let coordinates = (2, 2, 2)
let coordinates = (3, 0, 1)
let coordinates = (3, 2, 5)
let coordinates = (0, 2, 4)
介紹
歡迎來到Swift世界!Swift是一門蘋果在2014年夏天發布的編程語言。從那之后,Swift發布了一個主要的版本跳躍,成為了開始在蘋果平臺:iOS,OS X,watchOS和tvOS開發的最簡單的方式。
誰適合這篇教程
這篇教程適合懂一點編程、并且希望學習Swift的人。也許你已經為網站寫過一些JavaScript代碼,或者用Python寫過一些簡短的程序。這篇教程就是為你準備的!你會學習到編程的基本概念,同時也會成為Swift語言小能手。
如果你是赤裸裸的編程新手,這篇教程也是為你準備的!教程里貫穿有簡短的鍛煉和挑戰來給你一些編程練習,同時測試你的知識。
需要準備什么
要看這篇教程,你需要準備如下的東西:
- 一臺運行OS X El Captian(10.11)的Mac,帶有最新發布的更新并且安裝了安全補丁。這樣你才能夠安裝需要的開發工具:最新版本的Xcode。
- Xcode 7.3 或更新的版本。Xcode是用Swift寫代碼的主要開發工具。最小也需要Xcode 7.3版本,因為那個版本包含Swift 2.2。你可以免費從Mac App Store下載Xcode的最新版本,這里:http://apple.co/1FLn51R。
如果你還沒有安裝Xcode最新版本,在繼續看下面的教程前要確定安裝。
如何使用這篇教程
每篇教程都會介紹觸手可及的話題理論,伴隨大量Swift代碼來示范在學習的實際的應用程序。
教程里的所有代碼都是平臺中立的;這意味著不是為iOS、OS X或任何其它平臺而特定。代碼在playgrounds里運行,你在本篇中已經學習了。
在剩下的教程里,你可以把代碼在自己的playground里輸入進去。這樣你就可以和代碼“玩?!保╬lay around),做一些改變立即就能看見代碼運行的結果。
剩下的教程里會貫穿實際小練習,都是簡短的練習,關于觸手可及的主題。每篇的末尾也有挑戰,會有編程問題也會有長一點的代碼練習來測試你的知識。做完就能掌握大部分的Swift基礎知識。
教程更新
教程會隨Swift語言的更新而更新,會發布在我的簡書和知乎專欄上,搜索“張嘉夫”即可關注我。
目錄
本教程從一些基礎工作開始來讓你起步:
- 第1篇,編程本質 & Playground基礎 - 這就是,到編程世界的入門介紹!你會從電腦和編程的預覽開始,然后剩余時間給Swift playground打個招呼。
- 第2篇,變量 & 常量 - 你會學習到變量和常量,這是用來存儲數據的“地方”。你也會學習數據類型以及Swift如何追蹤數據類型并在代碼中進行傳輸。
- 第3篇,數字類型 & 操作 - 你會從基礎的數字類型比如整形和浮點型數字開始,當然也包括布爾類型。也會看到一些在實際操作,從比較到算數操作如加減。
- 第4篇,字符串 - 用字符串來存儲文字-從按鈕里的文字到圖片的標注到這篇教程全部的文字,存儲這所有的一切!你會學習到string和character類型,以及基于這些類型的一些常見操作。
在腦海中有基礎數據類型后,就該用那些數據做一些事情了:
- 第5篇,做判斷 - 代碼不總是直接從頭運行到尾。你會學習在代碼里如何做判決并且設定情況來運行某段代碼。
- 第6篇,重復步驟 - 繼續不要讓代碼直線運行的主題,你會學習到如何使用循環來重復某些步驟。
- 第7篇,函數 - 函數是Swift中用來構建代碼的基礎建筑。你會學習到如何定義函數來分組代碼到可復用單元中。
- 第8篇,閉包(Closures) - 閉包和函數很接近。你會學習到如何使用它們來輕松傳遞代碼塊。
最后一篇會回到數據:
- 第9節,可選值 - 這篇講可選值,Swift中的一種特殊類型,表示既有可能是一個真實的值也有可能沒有值。這篇的最后你會知道為什么要用可選值以及如何安全地使用它們。
這些基礎會讓你快速開始Swift之路,做好接觸更高級編程主題的準備。