iT邦幫忙

2025 iThome 鐵人賽

DAY 13
0
Mobile Development

Swift iOS 開發新手村:從入門到 AI 聊天室系列 第 13

Day 13|Swift 閉包入門:寫出精煉又強大的程式!

  • 分享至 

  • xImage
  •  

昨天我們深入了解了類別與結構,學會了如何將資料與功能有效組織起來。今天,我們要認識 Swift 中另一項更輕便、更靈活的利器:閉包(Closure)

簡單來說,閉包就像一個沒有名字的函式,可以像變數一樣被儲存和傳遞。但它最神奇的地方在於天生自帶「記憶力」:它能「捕獲」周遭的變數與常數,就算原始的程式區塊已經消失,閉包依然記得當時的狀態,並在需要時取用。

今日學習重點

  • 閉包語法:掌握表達式、多種簡化技巧與 尾隨閉包(Trailing Closure)
  • 核心特性:理解 捕獲值(Capturing Values)與逃逸閉包(Escaping Closure) 的概念。
  • 高階應用:學習 自動閉包(Autoclosure) 的延遲執行技巧。

閉包種類比較表

Swift 中的閉包有多種形式,依用途與特性略有不同。以下是幾種常見閉包的比較整理:

種類 關鍵字 特點與使用情境
一般閉包 最常見的閉包寫法,可捕獲外部變數
尾隨閉包 將閉包寫在函式呼叫括號外,讓程式碼更易讀
逃逸閉包 @escaping 閉包在函式執行結束後仍可被呼叫,例如非同步任務
自動閉包 @autoclosure 讓傳入的表達式延遲執行,常用於簡化語法或效能優化

閉包表達式:匿名函式的簡潔語法

閉包表達式可讓我們用簡潔的語法定義匿名函式,格式如下:

{ (參數列表) -> 返回值型別 in
    // 執行的程式碼
}

例如,我們有一個函式用來加總兩個整數:

func addTwoInts(number1: Int, number2: Int) -> Int {
    return number1 + number2
}

func printMathResult(_ mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) {
    print("結果是:\(mathFunction(a, b))")
}

printMathResult(addTwoInts, 12, 85) // 印出 結果是:97
// 使用閉包表達式
printMathResult({ (a: Int, b: Int) -> Int in a + b }, 12, 85)

閉包表達式的語法優化

Swift 提供多種語法簡化方式,讓閉包更精簡:

型別推斷:省略參數與回傳值型別

printMathResult({ number1, number2 in return number1 + number2 }, 12, 85)

隱式回傳:單一表達式時可省略 return

printMathResult({ number1, number2 in number1 + number2 }, 12, 85)

參數簡寫:使用 $0, $1 取代參數名稱

printMathResult({ $0 + $1 }, 12, 85)

運算子函式:直接傳入運算子符號

printMathResult(+, 12, 85)

以上寫法功能完全相同,依可讀性與習慣選擇使用即可。

尾隨閉包:增強程式碼可讀性

當函式的最後一個參數是閉包時,可以將閉包寫在函式括號外,提升可讀性。

func doSomething(message: String, completion: () -> Void) {
    print(message)
    completion()
}

未使用尾隨閉包時,寫法如下:

doSomething(message: "準備工作...", completion: {
    print("完成!")
})

使用尾隨閉包後,程式碼變得更像一個自然的流程控制區塊:

doSomething(message: "準備工作...") {
    print("完成!")
}

如果函式只有閉包一個參數,還可以省略括號:

func doSomethingElse(completion: () -> Void) {
    completion()
}

doSomethingElse {
    print("任務已執行。")
}

捕獲值:閉包的記憶能力

閉包可以捕捉並保存當時作用域中的變數,並在之後使用:

func makeIncrementer(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementer() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementer
}

let incrementByTen = makeIncrementer(forIncrement: 10)
print(incrementByTen()) // 10
print(incrementByTen()) // 20
print(incrementByTen()) // 30

每個閉包都獨立維護自己的狀態,互不影響。

閉包是參考型別,若多個變數指向同一閉包,會共用狀態。

逃逸閉包(Escaping Closure)

當閉包在函式執行完後才會被呼叫(例如非同步回呼),需加上 @escaping:

var completionHandlers: [() -> Void] = []

func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
    completionHandlers.append(completionHandler)
}

逃逸閉包內要顯式使用 self

class SomeClass {
    var x = 10
    func doSomething() {
        someFunctionWithEscapingClosure {
            self.x = 100
        }
    }
}

let instance = SomeClass()
instance.doSomething()
print(instance.x) // 10

completionHandlers.first?()
print(instance.x) // 100

為什麼逃逸閉包裡要寫 self?

這是 Swift 的一項安全特性。因為逃逸閉包會在函式結束後才被呼叫,它可能會「存活」得比它所屬的類別實體 (instance) 還要久。

Swift 強制你寫下 self,是在提醒你:「注意!這裡可能會產生記憶體管理的循環參考(Retain Cycle)問題」。它強迫你意識到你正在閉包中捕獲 self,需要多加留意。雖然現在還不用深入理解循環參考,但先記住這個「安全提醒」的設計用意。

自動閉包(Autoclosure)

自動閉包是一種語法糖,可以自動將表達式轉成閉包,讓函式呼叫看起來更自然。

func serve(customer customerProvider: () -> String) {
    print("準備服務顧客:\(customerProvider())")
}

var customersInLine = ["小明", "小華"]

serve(customer: { customersInLine.remove(at: 0) })

func serveWithAutoclosure(customer customerProvider: @autoclosure () -> String) {
    print("準備服務顧客:\(customerProvider())")
}

serveWithAutoclosure(customer: customersInLine.remove(at: 0))  // 更簡潔

注意:若要讓自動閉包同時也能逃逸,屬性需要同時宣告為 @autoclosure @escaping

小結一下

今天我們攻克了 Swift 中最靈活也最強大的功能之一:閉包(Closure)!我們學會了閉包就是「匿名的函式」,能夠捕獲其上下文中的變數,並擁有從完整到極致簡潔的多種語法優化形式。

我們還掌握了如何使用尾隨閉包來提升程式碼可讀性,並認識了逃逸閉包與自動閉包這兩種處理特殊情境的進階用法。徹底理解閉包,是寫出優雅、高效率 Swift 程式碼的關鍵。

🌟 明天預告

我們已經學會建立各種資料型別,但如何讓完全不同的型別(例如飛機)都能遵守同一套「規則」並保證擁有相同的功能(例如 fly())呢?

明天,我們就要來學習 Swift 中用來定義「行為藍圖」與「溝通合約」的超強工具:協定(Protocol)!你將學會如何定義一套所有型別都必須遵守的規範,並一窺它在 App 開發中的強大應用,例如 iOS 開發者面試必問的 委派模式(Delegate Pattern)

敬請期待《Day 14|Swift 協定導向程式設計:打造你的 Swift 程式規範!》


上一篇
Day 12|Swift 類別與結構:從零打造完美的資料藍圖
下一篇
Day 14|Swift 協定導向程式設計:打造你的 Swift 程式規範!
系列文
Swift iOS 開發新手村:從入門到 AI 聊天室16
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言