iT邦幫忙

2024 iThome 鐵人賽

DAY 14
0
Mobile Development

Swift iOS UIKit 初學者系列:從零開始開發互動式應用系列 第 14

【Day 14】Swift Delegate 和 Protocol -1:領包裹案例 - 單人通訊解析

  • 分享至 

  • xImage
  •  

導言

在iOS開發中,物件之間的通信至關重要,Delegate和Protocol正是實現這一目的的核心工具。這些概念初學者可能會感到陌生,覺得這些概念有點難以掌握,但理解它們後,你會發現它們不僅簡單實用,還能大幅提升應用程序的彈性和可維護性。

在第13天的文章中,我們探討了Unwind Segue作為一種資料傳遞的方式,能有效地返回上一個視圖控制器並傳遞資料。然而,Delegate和Protocol提供了更加靈活和強大的解決方案,尤其是在需要多個對象之間進行互動時。這篇文章將通過領包裹的案例來深入分析單人通訊的情境,幫助你更清楚地理解這些概念的實際應用。

在 iOS 開發中,Delegate 和 Protocol 是實現物件之間通信的核心機制。它們常常一同使用,協助不同的物件進行協同作業,而不需要強耦合。簡單來說,Delegate 讓一個對象可以將某些責任「委派」給另一個對象來完成,而 Protocol 則是一組規則,定義了應該實現的功能。

學習目標

  • 理解 Delegate 和 Protocol 的基本概念:了解在 iOS 開發中,如何使用 Delegate 和 Protocol 來實現物件之間的溝通與協作。
  • 學會實作委派模式:透過實際範例,學習如何定義 Protocol,並且實作 Delegate 以委派任務給不同的對象。
  • 掌握 Protocol 的應用場景:瞭解 Protocol 的作用與意義,並能在不同的情境下選擇適合的委派模式,從而提升程式設計的靈活性和可維護性。
  • 透過實例理解委派的運作方式:透過生活化的例子來簡化理解,幫助更清晰地掌握物件間的責任分配與互動方式。
  • 提升程式的架構設計能力:學會運用 Delegate 和 Protocol 的優勢,構建低耦合且可重用的程式架構。

生活化的例子

舉例來說:物件之間的通信和互動

// 定義一個委派協議
protocol MyDelegate: AnyObject {
    func didSomething()
}

// 類別允許使用 MyDelegate 協議作為委派
class MyClass {
    weak var delegate: MyDelegate?

    func performTask() {
        // 做一些事情

        // 通知委派
        delegate?.didSomething()
    }
}

// 實現委派協議的類別
class AnotherClass: MyDelegate {
    func didSomething() {
        print("AnotherClass did something.")
    }
}

// 使用
let myObject = MyClass()
let anotherObject = AnotherClass()

// 將 AnotherClass 設定為 MyClass 的委派
myObject.delegate = anotherObject

// MyClass 執行任務,會通知委派
myObject.performTask()

例子:領包裹通知
讓我們使用一個領包裹通知的例子來演示如何使用委派模式。這個例子涉及到守衛(SecurityGuard)、住戶(Resident)和領包裹通知(PackageDeliveryNotification)。

// 定義領包裹通知協議
protocol PackageDeliveryNotification: AnyObject {
    func notifyPackageReceived()
}

// 住戶類別 加入protocol,這樣守衛通知你就收的到
class Resident: PackageDeliveryNotification {
    let name: String
    init(name: String) { self.name = name }

    func notifyPackageReceived() {
        print("\(name) received a package notify. 📦")
    }
}

// 守衛類別 加入protocol,負責發出通知
class SecurityGuard {
    weak var deliveryDelegate: PackageDeliveryNotification?

    func deliverPackage() {
        // 守衛發送通知
        print("Security guard notifies residents about a delivered package.")

        // 通知住戶
        deliveryDelegate?.notifyPackageReceived()
    }
}

// 使用
let resident1 = Resident(name: "Alice")
let resident2 = Resident(name: "Bob")

let securityGuard = SecurityGuard()

// 將住戶設定為守衛的委派
securityGuard.deliveryDelegate = resident1

// 守衛送包裹,會通知住戶
securityGuard.deliverPackage()

// 將住戶更改為另一位
securityGuard.deliveryDelegate = resident2

// 守衛再次送包裹,會通知新的住戶
securityGuard.deliverPackage()

用自己的話再說一次

有點文縐縐的。一般來說,學到這段時,通常腦袋會打結,所以一定要用自己的話再說一次。

好,我們來聊聊會讓我們思維亂掉的地方 deliveryDelegate
deliveryDelegate 是代理的意思,但又是 protocol 協議型別? 最後卻將住戶指定給它。

物件之間的通信和互動

是指有二個物件,因為有個事件發生,他們要互動。會有

定義協議(protocol)和協議中的功能名稱。
任何希望收到通知的對象(物件B)都需要安裝這個協議(protocol),實作裡面的功能名稱和內容。
發出通知的對象(物件A)登記指定(物件B)。當事件發生時,(物件A)執行(物件B)協議中的功能名稱。

以我們大樓領包裹通知為例

1. 協議(protocol)的設計

定義協議(protocol)和協議中的功能名稱。

我們大樓的保全公司他們是用『智生活APP』來提供領包裹通知服務,所以protocol 的名稱叫 『智生活APP』,他裡面有 『領包裹通知() 』的服務

當然這裡的APP 你可以換成你們常用的如Line也行。

所以這段 protocol PackageDeliveryNotification 程式你可以這麼理解

// 定義領包裹通知協議
protocol 智生活APP: AnyObject {
    func 領包裹通知()
}
  1. 住戶的設計,住戶要安裝協議(protocol), 『智生活APP』
    任何希望收到通知的對象(物件B)都需要安裝這個協議(protocol),實作裡面的功能名稱和內容。

住戶要安裝 『智生活APP』,裝好後,有包裹事件時,守衛就會直接執行住戶的 『智生活APP』的『領包裹通知()』。

所以住戶要實作『領包裹通知()』功能,裡面要寫住戶要如何處理這個事件,例如準備磁扣到櫃檯領包裹

// 住戶類別 加入protocol,這樣守衛通知你就收的到
class 住戶: 智生活APP {
    let name: String
    init(name: String) { self.name = name }

    func 領包裹通知() {
        print("準備磁扣到櫃檯領包裹. 📦")
    }
}

但是有可能住戶沒裝APP,就會變成

// 住戶類別 你是不是忘了加入protocol,這樣守衛通知領包裹,你是收不到的唷
class 住戶 {
    let name: String
    init(name: String) { self.name = name }

    func 領包裹通知() {
        print("準備磁扣到櫃檯領包裹. 📦")
    }
}

或是這樣,住戶沒裝APP,也不知道可以領包裹

// 住戶類別 你是不網購的人,我了解
class 住戶 {
    let name: String
    init(name: String) { self.name = name }
}

3. 守衛的設計

發出通知的對象(物件A)登記指定(物件B)。當事件發生時,(物件A)執行(物件B)協議中的功能名稱。

要請住戶來登記,而且要請住戶裝 『智生活APP』

如果有包裹到,就執行這個住戶安裝『智生活APP』的 『領包裹通知()』

因為這個住戶他可能沒裝 『智生活APP』就來登記, 所以住戶後面要加問號表示有沒裝APP的可能。萬一執行了,就算他沒裝APP也沒關係,就只是單純住戶收不到通知而已,不會卡關,反正我通知了,裝不裝APP是住戶的事,我有請你要裝APP了。

// 守衛類別 加入protocol,負責發出通知
class 守衛 {
    weak var 登記的住戶: 智生活APP?

    func 領包裹通知() {
        // 守衛發送通知
        print("保全人員通知居民包裹已送達。")

        // 通知住戶,用 智生活APP 的 領包裹通知()
        登記的住戶?.領包裹通知()
    }
}

經過 1, 2, 3 步驟後,整個宣告工作就準備完成了。

接下來就是實際流程了。

  1. 有住戶 Alice 搬進來大樓,而且他也安裝『智生活APP』
  2. 守衛也來上班了。
  3. Alice 的包裹到了,守衛把登記的住戶指定為 Alice
  4. 執行 Alice 安裝『智生活APP』裡面的 領包裹通知()
let resident1 = 住戶(name: "Alice")
let securityGuard = 守衛()
securityGuard.登記的住戶 = resident1
securityGuard.領包裹通知()

錯誤狀況1 — 沒加入 protocol

  1. 住戶他忘了裝APP
class 住戶沒裝APP {
    let name: String
    init(name: String) { self.name = name }

    func 領包裹通知() {
        print("準備磁扣到櫃檯領包裹. 📦")
    }
}
  1. 守衛也來上班了。
  2. Jason 的包裹到了,守衛把登記的住戶指定為 Jason
let resident3 = 住戶沒裝APP(name: "Jason")
let securityGuard2 = 守衛()
securityGuard.登記的住戶 = resident3

發生錯誤

錯誤狀況2 — 有加入 protocol,但沒實作裡面的 Function

按了 Fix 後,會自動加上 func 領包裹通知() ,請你實作。

整理一下中文版的程式 XD

protocol 智生活APP: AnyObject {
    func 領包裹通知()
}

class 住戶: 智生活APP {
    let name: String
    init(name: String) { self.name = name }

    func 領包裹通知() {
        print("準備磁扣到櫃檯領包裹. 📦")
    }
}

class 守衛 {
    weak var 登記的住戶: 智生活APP?

    func 領包裹通知() {
        print("保全人員通知居民包裹已送達。")
        登記的住戶?.領包裹通知()
    }
}

let resident1 = 住戶(name: "Alice")
let securityGuard = 守衛()

securityGuard.登記的住戶 = resident1
securityGuard.領包裹通知()

就這樣,透過生活上的例子來對比,應該可以比較好記一下。

如果沒有住戶沒有裝 App ,沒有代理人裝的APP的幫忙,守衛就要自己去完成 領包裹通知() 裡的所有動作,現在只要交給住戶安裝的 App 去通知就好。一般在信箱上放牌子,也算是一種代理,只是沒那麼即時,但守衛一樣放完牌子就沒事了。

常見 UIKit 元件中的 Delegate 和 Protocol 應用

在實際應用中,Delegate 和 Protocol 被廣泛用於許多常見的 UIKit 元件。例如:

UITableViewDataSource – 表格視圖的資料來源協議,用於定義表格的資料呈現方式。
UITableViewDelegate – 表格視圖的委派協議,用於處理表格中的行選擇、編輯等互動。
UITextFieldDelegate – 文字輸入框的委派協議,用於處理輸入框的編輯行為(如開始或結束編輯、驗證內容等)。
這些例子展現了 delegate 和 protocol 的強大靈活性,允許我們在應用中處理複雜的互動邏輯,同時保持結構的清晰和可維護性。

回顧重點

  • Delegate 和 Protocol 是 iOS 中實現物件通信的重要概念,通常一起使用來解耦物件之間的緊密依賴。
  • Protocol 是一個協議,定義了需要實現的方法或屬性;Delegate 則是對象之間的代理,允許一個對象授權另一個對象執行某些操作。
  • 通過日常生活中的包裹領取通知例子來展示 delegate 模式的運作,包括定義協議(Protocol),讓住戶實作協議,以及讓守衛發送通知的步驟。
  • 常見 UIKit 元件中的 Delegate 和 Protocol 應用

結論

使用 Delegate 和 Protocol 可以讓應用程式的結構更具彈性和可維護性。這些技術使得物件之間能夠進行更加靈活的通信,而不需要彼此間的強耦合。透過包裹通知的範例,我們可以更清晰地理解這些概念,儘管這個例子,登記的住戶要換來換去不斷變動,很顯然不太符合生活的情況,但它展示了委派機制的運作原理。明天,我們將進一步探討多個物件之間的群體通信,並介紹更多實際應用情境。

附錄:已接觸的 UIKit 元件

  • Protocol 和 Delegate(Day 14) – 物件之間的通信機制,實現低耦合的資料傳遞與回應操作。
  • UITableViewDataSource(Day 14) – 表格視圖的資料來源協議,定義表格的資料呈現方式。
  • UITableViewDelegate(Day 14) – 表格視圖的委派協議,處理表格中的行選擇、編輯等互動。
  • UITextFieldDelegate(Day 14) – 文字輸入框的委派協議,處理輸入框的編輯行為。

上一篇
【Day 13】資料回傳與客製字型:應用 Unwind Segue 與字體設計強化 UI
下一篇
【Day 15】Swift Delegate 和 Protocol -2:群組通訊案例解析
系列文
Swift iOS UIKit 初學者系列:從零開始開發互動式應用27
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言