用 繁體中文 學習
Apple 官方程式語言 Swift
從零開始,掌握 Swift 核心概念、物件導向設計、非同步程式設計,打造屬於你的 iOS / macOS App!
var 與 let 的差異,以及 Swift 的不可變性設計哲學。Swift 介紹
認識這門由 Apple 打造的現代程式語言,了解它的特色與應用場景。
🍎 什麼是 Swift?
Swift 是由 Apple 於 2014 年發佈的現代程式語言,設計目標是取代 Objective-C,提供更安全、更快速、更簡潔的開發體驗。
Swift 是一門靜態型別語言,兼具表達力與效能,特別適合開發:
- iPhone / iPad App(iOS)
- Mac App(macOS)
- Apple Watch App(watchOS)
- Apple TV App(tvOS)
- 伺服器端應用程式(Linux / Windows)
🚀 為什麼選擇 Swift?
📅 Swift 發展歷程
| 年份 | 版本 | 重要里程碑 |
|---|---|---|
| 2014 | Swift 1.0 | 在 WWDC 首次發表,作為 Objective-C 的現代替代品 |
| 2015 | Swift 2.0 | 開放原始碼,支援 Linux 平台 |
| 2016 | Swift 3.0 | 大幅改善 API 命名規範 |
| 2017 | Swift 4.0 | Codable 協定、改善字串 API |
| 2019 | Swift 5.0 | ABI 穩定性,SwiftUI 發佈 |
| 2021 | Swift 5.5 | async/await 結構化並發 |
| 2022 | Swift 5.7 | 新型別推斷、正規表達式字面量 |
| 2024 | Swift 6.0 | 完整並發安全、嚴格並發檢查 |
💻 開發環境設置
安裝步驟(Mac)
- 開啟 Mac App Store
- 搜尋並安裝 Xcode(免費,約 12 GB)
- 開啟 Xcode,建立新的 Playground 即可開始撰寫 Swift 程式碼
👋 第一個 Swift 程式
按照傳統,我們先來看 Swift 版的 Hello World:
// 這是 Swift 的第一個程式
// 單行註解以 // 開頭
/*
多行註解使用 /* */ 包圍
*/
print("Hello, 世界!")
print("歡迎來到 Swift 的世界!")
// Swift 無需分號
let language = "Swift"
let version = 6.0
print("目前使用 \(language) \(version) 版")
;,也不需要 main() 入口函式(在腳本模式下)。語法基礎
掌握 Swift 的基本語法結構,包含 print、型別推斷、字串插值與函式入門。
🖨️ print() 輸出
Swift 使用 print() 函式輸出資訊到主控台。
// 基本 print 用法
print("Hello, Swift!")
// 輸出多個值(預設以空格分隔)
print("年齡:", 25, "歲")
// 自訂分隔符號
print("蘋果", "香蕉", "葡萄", separator: "、")
// 不換行輸出
print("載入中", terminator: "")
print("...")
// 輸出布林值
print(true, false)
💬 字串插值 String Interpolation
使用 \(運算式) 語法在字串中嵌入變數或運算式,這是 Swift 最常用的字串格式化方式。
let name = "小明"
let age = 20
let score = 95.5
// 基本字串插值
print("我是 \(name),今年 \(age) 歲")
// 嵌入運算式
print("明年我 \(age + 1) 歲")
// 數學計算
let price = 100
let quantity = 5
print("總金額:\(price * quantity) 元")
// 條件運算式
let isPassed = score >= 60
print("成績:\(score),\(isPassed ? "及格" : "不及格")")
📌 型別推斷 Type Inference
Swift 可以自動推斷變數的型別,但你也可以手動指定型別。
// 型別推斷(Swift 自動判斷)
let number = 42 // 推斷為 Int
let pi = 3.14159 // 推斷為 Double
let greeting = "Hello" // 推斷為 String
let flag = true // 推斷為 Bool
// 明確型別標注
let temperature: Double = 36
let count: Int = 100
let message: String = "Swift 好棒"
// 使用 type(of:) 查看型別
print(type(of: number)) // Int
print(type(of: pi)) // Double
print(type(of: greeting)) // String
💡 多行字串
// 使用三個雙引號建立多行字串
let poem = """
春眠不覺曉,
處處聞啼鳥。
夜來風雨聲,
花落知多少。
"""
let name = "Swift"
let version = 6
let info = """
語言:\(name)
版本:\(version)
公司:Apple Inc.
"""
print(poem)
print("---")
print(info)
變數與常數
理解 var 與 let 的核心差異,這是 Swift 設計哲學的重要基礎。
📦 var vs let
let birthYear = 2000
let PI = 3.14159
let appName = "MyApp"
// birthYear = 2001 // ❌ 錯誤!
var score = 0
var name = "未命名"
score = 100 // ✅ 可以修改
name = "Swift" // ✅ 可以修改
let,只有在需要修改的情況下才用 var。這能讓程式更安全、更容易理解。🔢 完整範例
// 常數 - 一旦設定就不能更改
let maxScore = 100
let playerName = "英雄聯盟玩家"
// 變數 - 可以修改
var currentScore = 0
var level = 1
var isAlive = true
print("玩家:\(playerName)")
print("目前關卡:\(level) 級")
print("目前分數:\(currentScore) / \(maxScore)")
// 升級
currentScore += 50
level += 1
print("\n升級後:")
print("關卡:\(level) 級")
print("分數:\(currentScore)")
// 多個變數同時宣告
var x = 0, y = 0, z = 0
print("\n座標:(\(x), \(y), \(z))")
❓ Optional 選擇型別
Swift 引入 Optional 型別來安全地處理「可能不存在的值」(nil)。
// 使用 ? 宣告 Optional
var nickname: String? = nil
var age: Int? = 25
print(nickname ?? "沒有暱稱") // nil 合并运算符
print(age ?? 0)
// 設定值
nickname = "Swift 學習者"
print(nickname!) // 強制解包(確定有值時才用)
// Optional 綁定(安全解包)
if let validAge = age {
print("年齡是:\(validAge)")
} else {
print("年齡未知")
}
// guard let 解包
func greet(name: String?) {
guard let unwrappedName = name else {
print("名字不存在")
return
}
print("你好,\(unwrappedName)!")
}
greet(name: "Alice")
greet(name: nil)
資料型別
Swift 的型別系統非常嚴格,了解各種型別是寫出安全程式的基礎。
📊 基本資料型別總覽
| 型別 | 說明 | 範例 | 預設值範圍 |
|---|---|---|---|
Int | 整數 | let n: Int = 42 | -9223372036854775808 ~ 9223372036854775807 |
Double | 64位浮點數(精確) | let d: Double = 3.14 | 精度約15-16位 |
Float | 32位浮點數 | let f: Float = 3.14 | 精度約6-7位 |
Bool | 布林值 | let b: Bool = true | true / false |
String | 字串 | let s = "Hello" | Unicode 字元序列 |
Character | 單一字元 | let c: Character = "A" | 單一 Unicode 字元 |
🔄 型別轉換
// Swift 不會自動轉換型別,需要明確轉換
let intValue: Int = 42
let doubleValue: Double = Double(intValue) // Int → Double
let floatValue: Float = Float(intValue) // Int → Float
print("\(intValue) → Double: \(doubleValue)")
print("\(intValue) → Float: \(floatValue)")
// Double → Int(截斷小數)
let pi = 3.99999
let intPi = Int(pi) // 3(不四捨五入,直接截斷)
print("π ≈ \(pi) → Int: \(intPi)")
// String ↔ Int
let numStr = "123"
if let num = Int(numStr) {
print("字串 \"\(numStr)\" 轉換為數字:\(num)")
}
let number = 456
let str = String(number)
print("數字 \(number) 轉換為字串:\"\(str)\"")
🔢 整數特殊功能
// 整數最大最小值
print("Int 最大值:\(Int.max)")
print("Int 最小值:\(Int.min)")
print("Int8 範圍:\(Int8.min) ~ \(Int8.max)")
// 不同進位系統
let decimal = 255
let binary = 0b11111111 // 二進位
let octal = 0o377 // 八進位
let hexadecimal = 0xFF // 十六進位
print("十進位:\(decimal)")
print("二進位:\(binary)")
print("八進位:\(octal)")
print("十六進位:\(hexadecimal)")
// 可讀性下劃線
let oneMillion = 1_000_000
let creditCard = 1234_5678_9012_3456
print("一百萬:\(oneMillion)")
運算子
Swift 提供豐富的運算子,從算術到範圍,幫你簡潔表達程式邏輯。
➕ 算術運算子
let a = 20
let b = 6
print(a + b) // 26 加法
print(a - b) // 14 減法
print(a * b) // 120 乘法
print(a / b) // 3 整數除法
print(a % b) // 2 取餘數
// 字串也支援 + 運算
let first = "Hello"
let second = " Swift"
print(first + second) // Hello Swift
// 複合賦值運算子
var score = 100
score += 50 // score = score + 50
score -= 20 // score = score - 20
score *= 2 // score = score * 2
score /= 3 // score = score / 3
print("分數:\(score)")
🔍 比較與邏輯運算子
// 比較運算子 - 返回 Bool
print(5 == 5) // true 等於
print(5 != 3) // true 不等於
print(5 > 3) // true 大於
print(5 < 10) // true 小於
print(5 >= 5) // true 大於等於
print(5 <= 4) // false 小於等於
// 邏輯運算子
let a = true
let b = false
print(a && b) // false AND:兩者都要 true
print(a || b) // true OR:至少一個 true
print(!a) // false NOT:取反
// 實際應用
let age = 25
let hasID = true
let canDrink = age >= 18 && hasID
print("可以喝酒:\(canDrink)")
📏 範圍運算子 Range Operators
Swift 獨特的範圍運算子,讓迴圈和陣列操作更直觀。
// 封閉範圍 a...b (包含 a 和 b)
for i in 1...5 {
print(i, terminator: " ")
}
print()
// 半開放範圍 a..
❓ 空合運算子 Nil-Coalescing
// ?? 運算子:若左邊為 nil,則使用右邊的預設值
var username: String? = nil
let displayName = username ?? "訪客"
print("歡迎,\(displayName)!") // 歡迎,訪客!
username = "SwiftLearner"
let displayName2 = username ?? "訪客"
print("歡迎,\(displayName2)!") // 歡迎,SwiftLearner!
// 三元運算子
let temperature = 35
let weather = temperature > 30 ? "好熱🔥" : "涼爽🌈"
print("天氣:\(weather)")
字串操作
Swift 的 String 是功能強大的值型別,支援 Unicode、豐富的方法與現代字串操作。
🔤 字串基本操作
var greeting = "Hello, Swift!"
// 基本屬性
print(greeting.count) // 13 字元數
print(greeting.isEmpty) // false 是否為空
print(greeting.uppercased()) // 全大寫
print(greeting.lowercased()) // 全小寫
// 包含 / 開頭 / 結尾 檢查
print(greeting.contains("Swift")) // true
print(greeting.hasPrefix("Hello")) // true
print(greeting.hasSuffix("!")) // true
// 字串替換
let newGreeting = greeting.replacingOccurrences(of: "Hello", with: "你好")
print(newGreeting) // 你好, Swift!
// 分割字串
let csv = "蘋果,香蕉,葡萄,西瓜"
let fruits = csv.split(separator: ",")
print(fruits) // ["蘋果", "香蕉", "葡萄", "西瓜"]
// 去除空白
let padded = " Hello "
print(padded.trimmingCharacters(in: .whitespaces))
🌏 Unicode 完整支援
// Swift 完整支援 Unicode
let emoji = "Swift 🐦 很棒!"
print(emoji)
print("字元數:\(emoji.count)")
// 遍歷每個字元
for char in "SWIFT" {
print(char, terminator: "-")
}
print()
// 中文字串
let chineseText = "學習程式設計,改變世界"
print(chineseText.count) // 11
// 字串比較
let str1 = "apple"
let str2 = "apple"
print(str1 == str2) // true
print(str1 < "banana") // true (字母順序)
條件判斷
讓程式根據不同條件執行不同邏輯,這是程式設計的核心能力之一。
🔀 if / else if / else
// 基本 if-else
let temperature = 28
if temperature >= 35 {
print("天氣很熱,注意防曬!")
} else if temperature >= 25 {
print("天氣溫暖舒適 ☀️")
} else if temperature >= 15 {
print("天氣有些涼,帶件外套")
} else {
print("天氣寒冷,多穿點!")
}
// 成績評分系統
let score = 78
let grade: String
if score >= 90 {
grade = "A(優秀)"
} else if score >= 80 {
grade = "B(良好)"
} else if score >= 70 {
grade = "C(普通)"
} else if score >= 60 {
grade = "D(及格)"
} else {
grade = "F(不及格)"
}
print("分數:\(score) → 等級:\(grade)")
🎯 if let — 安全解包
// if let 同時解包多個 optional(Swift 5.7+)
var firstName: String? = "Tim"
var lastName: String? = "Cook"
if let first = firstName, let last = lastName {
print("全名:\(first) \(last)")
}
// guard let 早退模式
func processAge(_ ageStr: String) {
guard let age = Int(ageStr), age >= 0 else {
print("無效的年齡輸入:\(ageStr)")
return
}
if age >= 18 {
print("年齡 \(age):成年人")
} else {
print("年齡 \(age):未成年")
}
}
processAge("25")
processAge("16")
processAge("abc")
Switch 語句
Swift 的 switch 遠比其他語言強大,支援模式匹配、範圍和多條件,且不需要 break!
🎛️ 基本 Switch
let day = 3
switch day {
case 1:
print("星期一 💼")
case 2:
print("星期二")
case 3:
print("星期三")
case 4, 5: // 多個值共用
print("星期四或五 🎉")
case 6, 7:
print("週末!😎")
default:
print("無效日期")
}
// 範圍匹配
let score = 85
switch score {
case 90...100:
print("優秀 🏆")
case 80..<90:
print("良好 ⭐")
case 70..<80:
print("普通")
case 60..<70:
print("及格")
default:
print("不及格 😢")
}
🔮 進階模式匹配
// 元組匹配
let point = (2, 0)
switch point {
case (0, 0):
print("原點")
case (_, 0):
print("X 軸上,x = \(point.0)")
case (0, _):
print("Y 軸上,y = \(point.1)")
case (-2...2, -2...2):
print("在中央區域")
default:
print("其他位置")
}
// where 條件
let number = 42
switch number {
case let n where n < 0:
print("\(n) 是負數")
case let n where n % 2 == 0:
print("\(n) 是偶數")
case let n where n % 2 != 0:
print("\(n) 是奇數")
default:
break
}
迴圈
for-in、while、repeat-while 三種迴圈各有適用場景,靈活運用讓程式簡潔有力。
🔁 for-in 迴圈
// 數字範圍
print("=== 1到5 ===")
for i in 1...5 {
print(i, terminator: " ")
}
print()
// 遍歷陣列
let planets = ["水星", "金星", "地球", "火星"]
for planet in planets {
print("行星:\(planet)")
}
// 帶索引遍歷
for (index, planet) in planets.enumerated() {
print("\(index + 1). \(planet)")
}
// stride - 自訂步長
print("\n偶數:", terminator: "")
for i in stride(from: 0, to: 11, by: 2) {
print(i, terminator: " ")
}
print("\n倒數:", terminator: "")
for i in stride(from: 10, through: 0, by: -2) {
print(i, terminator: " ")
}
⏰ while / repeat-while
// while - 先判斷再執行
var countdown = 5
print("發射倒計時:")
while countdown > 0 {
print("\(countdown)...")
countdown -= 1
}
print("🚀 發射!")
// repeat-while - 至少執行一次(類似 do-while)
var password = ""
var attempts = 0
repeat {
attempts += 1
password = attempts == 3 ? "swift123" : "wrong"
print("第 \(attempts) 次嘗試")
} while password != "swift123"
print("✅ 登入成功!")
// break 和 continue
print("\n跳過 3 的倍數:", terminator: "")
for i in 1...10 {
if i % 3 == 0 { continue } // 跳過
print(i, terminator: " ")
}
陣列 Array
陣列是有序的元素集合,Swift 提供強大的高階函式讓操作更優雅。
📋 建立與操作陣列
// 建立陣列
var fruits = ["蘋果", "香蕉", "葡萄"]
var numbers: [Int] = [1, 2, 3, 4, 5]
var emptyArray: [String] = []
// 存取元素
print(fruits[0]) // 蘋果
print(fruits.first!) // 蘋果
print(fruits.last!) // 葡萄
print(fruits.count) // 3
// 修改陣列
fruits.append("西瓜") // 加到末尾
fruits.insert("草莓", at: 1) // 插入特定位置
fruits.remove(at: 0) // 刪除索引 0
fruits[0] = "鳳梨" // 修改元素
print(fruits)
// 常用屬性
print("是否為空:\(fruits.isEmpty)")
print("包含西瓜:\(fruits.contains("西瓜"))")
⚡ 高階函式 map / filter / reduce
let scores = [45, 82, 61, 93, 55, 78, 88]
// map - 轉換每個元素
let doubled = scores.map { $0 * 2 }
print("加倍:\(doubled)")
// filter - 過濾元素
let passing = scores.filter { $0 >= 60 }
print("及格的:\(passing)")
// reduce - 聚合計算
let total = scores.reduce(0) { $0 + $1 }
let average = Double(total) / Double(scores.count)
print("總分:\(total)")
print("平均:\(String(format: "%.1f", average))")
// sorted
let sorted = scores.sorted()
let sortedDesc = scores.sorted(by: >)
print("升序:\(sorted)")
print("降序:\(sortedDesc)")
// 鏈式操作:過濾及格成績,轉為等級
let grades = scores
.filter { $0 >= 60 }
.map { score -> String in
switch score {
case 90...100: return "A"
case 80..<90: return "B"
case 70..<80: return "C"
default: return "D"
}
}
print("等級:\(grades)")
函式 Function
函式是 Swift 的核心概念,支援靈活的參數標籤、預設值、可變參數與多返回值。
⚙️ 函式基本語法
// 基本函式
func greet(name: String) -> String {
return "你好,\(name)!"
}
print(greet(name: "小明"))
// 多個參數
func add(_ a: Int, _ b: Int) -> Int {
return a + b
}
print(add(3, 5))
// 預設參數值
func createProfile(name: String, age: Int = 18, role: String = "用戶") -> String {
return "\(name)(\(age)歲)- \(role)"
}
print(createProfile(name: "Alice"))
print(createProfile(name: "Bob", age: 25, role: "管理員"))
// 回傳多個值(使用元組)
func minMax(_ array: [Int]) -> (min: Int, max: Int) {
return (array.min()!, array.max()!)
}
let result = minMax([5, 3, 8, 1, 9, 2])
print("最小:\(result.min),最大:\(result.max)")
// 可變參數
func sum(_ numbers: Int...) -> Int {
return numbers.reduce(0, +)
}
print(sum(1, 2, 3, 4, 5))
🏷️ 參數標籤
// 外部標籤 內部標籤: 型別
func move(from startPoint: String, to endPoint: String) {
print("從 \(startPoint) 移動到 \(endPoint)")
}
// 呼叫時使用外部標籤
move(from: "台北", to: "高雄")
// 使用 _ 省略外部標籤
func multiply(_ x: Int, by y: Int) -> Int {
return x * y
}
print(multiply(6, by: 7))
// @discardableResult - 可以忽略回傳值
@discardableResult
func saveToDatabase(data: String) -> Bool {
print("儲存:\(data)")
return true
}
saveToDatabase(data: "用戶資料")
閉包 Closure
閉包是自包含的程式碼區塊,可以捕獲環境中的值,是 Swift 函數式程式設計的核心。
🎯 閉包語法演進
// 完整閉包語法
let fullClosure = { (x: Int, y: Int) -> Int in
return x + y
}
// 省略型別(推斷)
let shortClosure = { (x: Int, y: Int) in x + y }
// 使用 $0, $1 簡寫參數
let minimal = { $0 + $1 }
print(fullClosure(3, 4)) // 7
print(shortClosure(3, 4)) // 7
print(minimal(3, 4)) // 7
// 尾隨閉包(最後一個參數是閉包)
let numbers = [5, 2, 8, 1, 9]
// 標準寫法
let sorted1 = numbers.sorted(by: { (a, b) -> Bool in return a < b })
// 尾隨閉包
let sorted2 = numbers.sorted { $0 < $1 }
print(sorted2) // [1, 2, 5, 8, 9]
// 實際應用:非同步回調
func fetchData(completion: (String) -> Void) {
let data = "來自伺服器的資料"
completion(data)
}
fetchData { data in
print("收到:\(data)")
}
📸 捕獲值 Capture Values
// 閉包可以捕獲並修改外部變數
func makeCounter() -> () -> Int {
var count = 0
return {
count += 1
return count
}
}
let counter1 = makeCounter()
let counter2 = makeCounter()
print(counter1()) // 1
print(counter1()) // 2
print(counter1()) // 3
print(counter2()) // 1(獨立計數器)
print(counter2()) // 2
結構體 Struct
結構體是 Swift 最重要的型別之一,值型別語意讓程式碼更安全、更可預測。
🧱 定義與使用結構體
struct Player {
var name: String
var health: Int
var level: Int
// 計算屬性
var isAlive: Bool {
return health > 0
}
var description: String {
return "\(name) (等級\(level), 血量\(health))"
}
// Mutating 方法(修改 struct 需加 mutating)
mutating func takeDamage(_ damage: Int) {
health = max(0, health - damage)
print("\(name) 受到 \(damage) 點傷害,剩餘血量:\(health)")
}
mutating func levelUp() {
level += 1
health = min(100, health + 20)
print("\(name) 升級到 \(level) 級!")
}
}
var hero = Player(name: "英雄", health: 100, level: 1)
print(hero.description)
hero.takeDamage(30)
hero.levelUp()
print("存活中:\(hero.isAlive)")
類別 Class
類別是參考型別,支援繼承與多型,適合代表需要共享狀態的複雜物件。
🏛️ 類別定義與繼承
// 基礎類別
class Animal {
var name: String
var sound: String
init(name: String, sound: String) {
self.name = name
self.sound = sound
}
func speak() {
print("\(name) 說:\(sound)!")
}
deinit {
// 物件被銷毀時呼叫
print("\(name) 離開了")
}
}
// 繼承
class Dog: Animal {
var breed: String
init(name: String, breed: String) {
self.breed = breed
super.init(name: name, sound: "汪汪")
}
// 覆寫父類別方法
override func speak() {
print("🐕 \(name)(\(breed)):\(sound)!搖尾巴中...")
}
func fetch() {
print("\(name) 去撿球了!🎾")
}
}
let animal = Animal(name: "動物", sound: "...")
let dog = Dog(name: "小黑", breed: "柴犬")
animal.speak()
dog.speak()
dog.fetch()
// 型別檢查
print(dog is Animal) // true(繼承關係)
print(dog is Dog) // true
⚖️ Class vs Struct
| 特性 | Class(類別) | Struct(結構體) |
|---|---|---|
| 型別 | 參考型別 Reference | 值型別 Value |
| 繼承 | ✅ 支援 | ❌ 不支援 |
| 記憶體 | Heap(堆疊) | Stack(棧) |
| 複製行為 | 共享同一個物件 | 複製獨立副本 |
| deinit | ✅ 支援 | ❌ 不支援 |
| 適用場景 | 共享狀態、繼承關係 | 簡單資料模型、值語意 |
struct,只有在需要繼承或共享狀態時才使用 class。協定 Protocol
Protocol 是 Swift 的核心設計模式,提供比繼承更靈活的程式碼復用方式。
🤝 定義與實作協定
// 定義協定
protocol Drawable {
var color: String { get }
func draw()
func area() -> Double
}
protocol Resizable {
mutating func resize(by factor: Double)
}
// 結構體遵守多個協定
struct Circle: Drawable, Resizable {
var radius: Double
var color: String
func draw() {
print("畫一個 \(color) 的圓形,半徑 \(radius)")
}
func area() -> Double {
return Double.pi * radius * radius
}
mutating func resize(by factor: Double) {
radius *= factor
}
}
struct Rectangle: Drawable {
var width: Double
var height: Double
var color: String
func draw() {
print("畫一個 \(color) 的矩形 \(width) × \(height)")
}
func area() -> Double {
return width * height
}
}
// 協定型別使用
var shapes: [any Drawable] = [
Circle(radius: 5.0, color: "紅色"),
Rectangle(width: 4.0, height: 3.0, color: "藍色")
]
for shape in shapes {
shape.draw()
print(" 面積:\(String(format: "%.2f", shape.area()))")
}
非同步並發
Swift 5.5+ 引入的 async/await、Task 和 Actor 讓並發程式設計更安全直觀。
⚡ async / await
import Foundation
// 定義非同步函式
func fetchUserName(id: Int) async throws -> String {
// 模擬網路延遲
try await Task.sleep(nanoseconds: 1_000_000_000)
let users = [1: "Alice", 2: "Bob", 3: "Charlie"]
guard let name = users[id] else {
throw URLError(.badURL)
}
return name
}
// 並發執行多個非同步任務
func fetchMultipleUsers() async {
async let user1 = fetchUserName(id: 1)
async let user2 = fetchUserName(id: 2)
// 等待兩個任務都完成
do {
let (name1, name2) = try await (user1, user2)
print("用戶 1:\(name1)")
print("用戶 2:\(name2)")
} catch {
print("錯誤:\(error)")
}
}
// Task - 啟動非同步任務
Task {
await fetchMultipleUsers()
}
// Actor - 執行緒安全的共享狀態
actor BankAccount {
private var balance: Double = 0
func deposit(_ amount: Double) {
balance += amount
print("存入 \(amount),餘額:\(balance)")
}
func withdraw(_ amount: Double) -> Bool {
guard balance >= amount else {
print("餘額不足!")
return false
}
balance -= amount
print("提款 \(amount),餘額:\(balance)")
return true
}
}
// 使用 Actor
Task {
let account = BankAccount()
await account.deposit(1000)
await account.withdraw(300)
await account.withdraw(800) // 餘額不足
}
🔄 結構化並發 Structured Concurrency
| 概念 | 說明 | 使用場景 |
|---|---|---|
async func | 宣告非同步函式 | 需要等待的操作(網路、檔案) |
await | 等待非同步結果 | 呼叫 async 函式時使用 |
async let | 並發啟動多個任務 | 同時執行多個獨立請求 |
Task | 建立非同步任務 | 從同步程式碼啟動非同步工作 |
TaskGroup | 動態並發任務組 | 批量處理不定數量的任務 |
actor | 執行緒安全的類別 | 共享狀態的並發安全保護 |
字典 Dictionary
字典是鍵值對的集合,提供 O(1) 的查詢速度,非常適合快速查找的場景。
📖 建立與操作字典
// 建立字典
var scores: [String: Int] = ["Alice": 95, "Bob": 82, "Charlie": 78]
var capitals = ["台灣": "台北", "日本": "東京", "美國": "華盛頓"]
// 讀取(返回 Optional)
if let aliceScore = scores["Alice"] {
print("Alice 的分數:\(aliceScore)")
}
// 使用 ?? 提供預設值
let davidScore = scores["David"] ?? 0
print("David 的分數:\(davidScore)")
// 新增 / 修改
scores["David"] = 90
scores["Alice"] = 98 // 修改
// 刪除
scores.removeValue(forKey: "Bob")
scores["Charlie"] = nil // 另一種刪除方式
print("字典:\(scores)")
print("人數:\(scores.count)")
// 遍歷字典
for (name, score) in scores.sorted(by: { $0.value > $1.value }) {
print("\(name): \(score) 分")
}
// 取出所有鍵 / 值
print("所有人:\(Array(scores.keys))")
print("所有分數:\(Array(scores.values))")
集合 Set
Set 是無序且唯一元素的集合,支援數學集合運算,適合去重和快速查找。
🔵 Set 基本操作
// 建立 Set(需明確型別標注)
var fruits: Set = ["蘋果", "香蕉", "葡萄", "蘋果"]
// 重複的「蘋果」只會存一個
print(fruits)
print("元素數量:\(fruits.count)")
// 集合運算
let setA: Set = [1, 2, 3, 4, 5]
let setB: Set = [3, 4, 5, 6, 7]
print("聯集:\(setA.union(setB).sorted())")
print("交集:\(setA.intersection(setB).sorted())")
print("差集:\(setA.subtracting(setB).sorted())")
print("對稱差集:\(setA.symmetricDifference(setB).sorted())")
// 子集 / 超集 判斷
let setC: Set = [3, 4]
print("setC 是 setA 的子集:\(setC.isSubset(of: setA))")
print("setA 是 setC 的超集:\(setA.isSuperset(of: setC))")
// 陣列去重
let arr = [1, 2, 2, 3, 3, 3, 4]
let unique = Array(Set(arr)).sorted()
print("去重後:\(unique)")
選擇型別 Optional
Optional 是 Swift 的安全機制,用來表示「值可能不存在」,避免空指針崩潰。
❓ Optional 完整教學
// Optional 宣告
var name: String? = "Swift"
var age: Int? = nil
// 1. 可選鏈 Optional Chaining
let count = name?.count // 若 name 為 nil 則返回 nil
print(count ?? 0)
// 2. if let 安全解包
if let unwrappedName = name {
print("名字:\(unwrappedName)")
}
// 3. guard let 早退
func printAge(_ age: Int?) {
guard let age = age else {
print("年齡不明")
return
}
print("年齡:\(age)")
}
printAge(25)
printAge(nil)
// 4. ?? 空合運算子
let displayAge = age ?? 18
print("顯示年齡:\(displayAge)")
// 5. 可選鏈連鎖
struct Address { var city: String? }
struct Person { var address: Address? }
let person = Person(address: Address(city: "台北"))
let city = person.address?.city ?? "未知城市"
print("城市:\(city)")
// 6. 強制解包(謹慎使用!)
let safeValue: String? = "確定有值"
print(safeValue!) // 確定有值時才用 !
列舉 Enum
Swift 的 enum 是強大的型別,支援關聯值、原始值和方法,遠超其他語言的列舉。
🏷️ 列舉進階用法
// 基本列舉
enum Direction {
case north, south, east, west
}
let dir = Direction.north
print(dir)
// 帶原始值的列舉
enum Planet: Int {
case mercury = 1, venus, earth, mars
var description: String {
switch self {
case .earth: return "我們的家鄉 🌍"
case .mars: return "未來的移民地 🔴"
default: return "神秘星球"
}
}
}
let earth = Planet.earth
print("\(earth):\(earth.description)")
print("地球是第 \(earth.rawValue) 顆行星")
// 帶關聯值的列舉(Swift 最強大的特性之一)
enum PaymentMethod {
case cash(amount: Double)
case creditCard(number: String, expiry: String)
case applePay(phoneLastFour: String)
}
let payment = PaymentMethod.creditCard(number: "1234", expiry: "12/26")
switch payment {
case .cash(let amount):
print("現金:\(amount) 元")
case .creditCard(let num, let exp):
print("信用卡:\(num),到期:\(exp)")
case .applePay(let phone):
print("Apple Pay:\(phone)")
}
泛型 Generics
泛型讓你撰寫可重複使用的程式碼,同時保持型別安全,是 Swift 標準庫的基礎。
🔷 泛型函式與型別
// 泛型函式
func swap(_ a: inout T, _ b: inout T) {
let temp = a
a = b
b = temp
}
var x = 10, y = 20
swap(&x, &y)
print("x=\(x), y=\(y)")
var str1 = "Hello", str2 = "World"
swap(&str1, &str2)
print("\(str1) \(str2)")
// 泛型型別(Stack 堆疊)
struct Stack {
private var items: [Element] = []
mutating func push(_ item: Element) {
items.append(item)
}
mutating func pop() -> Element? {
return items.popLast()
}
var top: Element? {
return items.last
}
var isEmpty: Bool { items.isEmpty }
var count: Int { items.count }
}
var stack = Stack()
stack.push(1)
stack.push(2)
stack.push(3)
print("堆疊頂端:\(stack.top!)")
print("彈出:\(stack.pop()!)")
print("剩餘:\(stack.count) 個")
// 型別約束
func findMax(_ array: [T]) -> T? {
return array.max()
}
print(findMax([3, 1, 4, 1, 5, 9])!)
print(findMax(["banana", "apple", "cherry"])!)
錯誤處理
Swift 提供完整的錯誤處理機制,讓你的程式在面對異常情況時優雅地應對。
🛡️ throw / try / catch
// 定義錯誤型別
enum LoginError: Error {
case emptyUsername
case emptyPassword
case invalidCredentials
case accountLocked(reason: String)
}
// 會拋出錯誤的函式
func login(username: String, password: String) throws -> String {
guard !username.isEmpty else { throw LoginError.emptyUsername }
guard !password.isEmpty else { throw LoginError.emptyPassword }
if username == "admin" && password == "swift123" {
return "歡迎回來,\(username)!"
} else if username == "blocked" {
throw LoginError.accountLocked(reason: "多次輸入錯誤密碼")
} else {
throw LoginError.invalidCredentials
}
}
// do-try-catch 處理錯誤
func attemptLogin(_ user: String, _ pass: String) {
do {
let message = try login(username: user, password: pass)
print("✅ \(message)")
} catch LoginError.emptyUsername {
print("❌ 請輸入用戶名")
} catch LoginError.emptyPassword {
print("❌ 請輸入密碼")
} catch LoginError.invalidCredentials {
print("❌ 用戶名或密碼錯誤")
} catch LoginError.accountLocked(let reason) {
print("🔒 帳號已鎖定:\(reason)")
} catch {
print("未知錯誤:\(error)")
}
}
attemptLogin("admin", "swift123")
attemptLogin("", "pass")
attemptLogin("admin", "wrong")
attemptLogin("blocked", "pass")
// defer - 確保執行清理工作
func readFile(name: String) throws {
print("📂 開啟檔案:\(name)")
defer {
print("📁 關閉檔案:\(name)") // 一定會執行
}
// 模擬讀取
print("📖 讀取內容...")
if name == "secret.txt" {
throw LoginError.invalidCredentials
}
print("✅ 讀取完成")
}
try? readFile(name: "data.txt")
print("---")
try? readFile(name: "secret.txt")
Swift 知識測驗
測試你對 Swift 的掌握程度!完成後查看解說,鞏固學習成果。
Hello, Swift!?Int? 代表什麼型別?let arr = [1,2,3,4,5].filter { $0 % 2 == 0 }.map { $0 * 3 }print(arr)struct 和 class 最主要的差異是什麼?guard let 與 if let 最主要的差異是什麼?actor 的主要用途是什麼?