代理(Delegate)、閉包(Closure)、Notification(通知中心) 和 swift_event_bus適用場景和工作方式

在 Swift 開發中,在 Swift 開發中,代理(Delegate)、閉包(Closure)、Notification(通知中心) 和 swift_event_bus 主要用于 組件之間的通信,但它們的適用場景和工作方式有所不同。以下是它們的區別:

1. 代理(Delegate)

? ? 適用場景:適用于 一對一 通信,通常用于傳遞事件或回調,例如 UITableViewDelegate。

? ? 實現方式:使用 協議(Protocol) 定義代理方法,調用方實現代理協議并傳遞代理對象。

? ? 特點

? ? 強類型檢查,編譯時安全。

? ? 適用于長期存在的關系(如 UITableView 和 UITableViewDelegate)。

? ? 需要顯式聲明代理,并手動設置代理對象。

代碼示例:

protocol PlayerDelegate: AnyObject {func didFinishPlaying()
}class MusicPlayer {weak var delegate: PlayerDelegate?func play() {// 模擬播放完成delegate?.didFinishPlaying()}
}class ViewController: PlayerDelegate {let player = MusicPlayer()init() {player.delegate = selfplayer.play()}func didFinishPlaying() {print("播放完成")}
}

一個 protocol 可以在多個控制器中實現,這正是 Swift 協議的強大之處。協議(protocol)定義了一組方法和屬性,任何類、結構體或枚舉都可以遵循并實現這個協議,這允許你在多個 UIViewController 中實現相同的協議邏輯。

示例:一個協議在多個控制器中實現

假設你的 myMusic 項目中有一個播放器,你希望不同的控制器(比如 HomeViewController 和 PlaylistViewController)都能夠監聽播放器的播放完成事件,你可以這樣做:

1. 定義一個協議

protocol MusicPlayerDelegate: AnyObject {func didFinishPlaying(song: String)
}

2. 在多個控制器中實現協議

第一個控制器:HomeViewController

class HomeViewController: UIViewController, MusicPlayerDelegate {override func viewDidLoad() {super.viewDidLoad()MusicPlayer.shared.delegate = self}func didFinishPlaying(song: String) {print("HomeViewController: \(song) 播放完成,更新 UI")}
}

第二個控制器:PlaylistViewController

class PlaylistViewController: UIViewController, MusicPlayerDelegate {override func viewDidLoad() {super.viewDidLoad()MusicPlayer.shared.delegate = self}func didFinishPlaying(song: String) {print("PlaylistViewController: \(song) 播放完成,刷新播放列表")}
}

問題:協議的 delegate 只能有一個對象

上面代碼的 問題 是 MusicPlayer.shared.delegate 只能存儲 一個 代理對象(即最后設置的那個),所以如果 PlaylistViewController 先設置了代理,而 HomeViewController 后設置代理,就會覆蓋之前的代理。

解決方案 1:使用數組存儲多個代理

如果你希望 多個控制器 都能監聽播放器事件,可以改進 MusicPlayer,讓它支持多個代理:

class MusicPlayer {static let shared = MusicPlayer()private var delegates = [MusicPlayerDelegate]()func addDelegate(_ delegate: MusicPlayerDelegate) {delegates.append(delegate)}func removeDelegate(_ delegate: MusicPlayerDelegate) {delegates.removeAll { $0 === delegate }}func play() {// 模擬播放完成notifyDelegates(song: "My Favorite Song")}private func notifyDelegates(song: String) {for delegate in delegates {delegate.didFinishPlaying(song: song)}}
}

使用方式

override func viewDidLoad() {super.viewDidLoad()MusicPlayer.shared.addDelegate(self)
}

解決方案 2:使用 NotificationCenter(適用于全局事件)

如果你不想手動管理多個代理數組,可以用 NotificationCenter 代替:

class MusicPlayer {static let shared = MusicPlayer()func play() {// 模擬播放完成,發送通知NotificationCenter.default.post(name: .musicFinished, object: nil, userInfo: ["song": "My Favorite Song"])}
}extension Notification.Name {static let musicFinished = Notification.Name("musicFinished")
}

在多個控制器中監聽

NotificationCenter.default.addObserver(self, selector: #selector(musicFinished(_:)), name: .musicFinished, object: nil)@objc func musicFinished(_ notification: Notification) {if let song = notification.userInfo?["song"] as? String {print("收到通知:\(song) 播放完成")}
}

總結

方法適用場景優點缺點
Delegate 單個對象一對一通信類型安全,編譯時檢查只能有一個代理
Delegate 多個對象多個對象監聽所有監聽者都能收到回調需要手動管理代理數組
NotificationCenter全局事件解耦,不限監聽者數量運行時檢查,代碼可讀性略低

如果希望 多個控制器 監聽同一事件:

? ? 需要 強類型回調 → 用 多個 delegate(數組方式)

? ? 需要 全局廣播 → 用 NotificationCenter

2. 閉包(Closure)

? ? 適用場景:適用于 一對一臨時性 事件回調,例如網絡請求完成后回調。

? ? 實現方式:將 函數作為參數 傳遞,通常用于短生命周期的任務,如異步操作或 UI 交互。

? ? 特點

? ? 代碼簡潔,適合短期任務。

? ? 避免定義額外的協議和類。

? ? 容易導致循環引用(需注意 [weak self])。

代碼示例:

class MusicPlayer {var onFinishPlaying: (() -> Void)?func play() {// 模擬播放完成onFinishPlaying?()}
}let player = MusicPlayer()
player.onFinishPlaying = {print("播放完成")
}
player.play()

3. Notification(通知中心)

? ? 適用場景:適用于 一對多 通信,例如全局狀態變化、系統廣播(如鍵盤彈出)。

? ? 實現方式:使用 NotificationCenter 發送和監聽通知。

? ? 特點

? ? 解耦性高,不需要直接引用發送者。

? ? 適用于全局事件,如應用生命周期、網絡狀態變化等。

? ? 可能導致代碼難以跟蹤,容易造成資源泄漏(監聽后需移除)。

代碼示例:

// 發送通知
NotificationCenter.default.post(name: NSNotification.Name("MusicFinished"), object: nil)// 監聽通知
NotificationCenter.default.addObserver(self, selector: #selector(musicFinished), name: NSNotification.Name("MusicFinished"), object: nil)@objc func musicFinished() {print("播放完成")
}

4. swift_event_bus(事件總線)

? ? 適用場景:適用于 一對多多對多 事件傳遞,通常用于解耦模塊間的通信。

? ? 實現方式:通過 SwiftEventBus 發布和訂閱事件。

? ? 特點

? ? 類似 NotificationCenter,但更輕量級,支持異步和線程調度。

? ? 適用于模塊化架構,如 MVVM、VIPER。

? ? 易用性比 NotificationCenter 更高,但不如 delegate 和 closure 類型安全。

代碼示例:

import SwiftEventBus// 訂閱事件
SwiftEventBus.onMainThread(self, name: "MusicFinished") { result inprint("播放完成")
}// 發送事件
SwiftEventBus.post("MusicFinished")

總結對比

方式適用場景關系類型適用范圍代碼復雜度解耦性
代理(Delegate)長期一對一通信一對一UI 組件、數據回調
閉包(Closure)短期回調一對一異步任務、臨時事件
Notification一對多通信一對多全局事件、廣播
swift_event_bus模塊間解耦一對多/多對多事件驅動架構

選擇建議

? ? 一對一且長期的關系(如 UITableView)→ Delegate

? ? 一對一且是短期任務(如異步回調)→ Closure

? ? 一對多或全局事件(如 App 生命周期)→ NotificationCenter

? ? 解耦多個模塊的通信(如 MVVM)→ swift_event_bus

你目前的 myMusic 項目如果涉及 UI 組件間的通信,比如播放器狀態更新,建議:

? ? 使用 Delegate 處理播放器的狀態回調。

? ? 使用 Closure 處理網絡請求回調。

? ? 使用 NotificationCenter 或 swift_event_bus 處理全局事件(如登錄成功、歌曲切換)。

主要用于 組件之間的通信,但它們的適用場景和工作方式有所不同。以下是它們的區別:

1. 代理(Delegate)

? ? 適用場景:適用于 一對一 通信,通常用于傳遞事件或回調,例如 UITableViewDelegate。

? ? 實現方式:使用 協議(Protocol) 定義代理方法,調用方實現代理協議并傳遞代理對象。

? ? 特點

? ? 強類型檢查,編譯時安全。

? ? 適用于長期存在的關系(如 UITableView 和 UITableViewDelegate)。

? ? 需要顯式聲明代理,并手動設置代理對象。

代碼示例:

protocol PlayerDelegate: AnyObject {func didFinishPlaying()
}class MusicPlayer {weak var delegate: PlayerDelegate?func play() {// 模擬播放完成delegate?.didFinishPlaying()}
}class ViewController: PlayerDelegate {let player = MusicPlayer()init() {player.delegate = selfplayer.play()}func didFinishPlaying() {print("播放完成")}
}

2. 閉包(Closure)

? ? 適用場景:適用于 一對一臨時性 事件回調,例如網絡請求完成后回調。

? ? 實現方式:將 函數作為參數 傳遞,通常用于短生命周期的任務,如異步操作或 UI 交互。

? ? 特點

? ? 代碼簡潔,適合短期任務。

? ? 避免定義額外的協議和類。

? ? 容易導致循環引用(需注意 [weak self])。

代碼示例:

class MusicPlayer {var onFinishPlaying: (() -> Void)?func play() {// 模擬播放完成onFinishPlaying?()}
}let player = MusicPlayer()
player.onFinishPlaying = {print("播放完成")
}
player.play()

3. Notification(通知中心)

? ? 適用場景:適用于 一對多 通信,例如全局狀態變化、系統廣播(如鍵盤彈出)。

? ? 實現方式:使用 NotificationCenter 發送和監聽通知。

? ? 特點

? ? 解耦性高,不需要直接引用發送者。

? ? 適用于全局事件,如應用生命周期、網絡狀態變化等。

? ? 可能導致代碼難以跟蹤,容易造成資源泄漏(監聽后需移除)。

代碼示例:

// 發送通知
NotificationCenter.default.post(name: NSNotification.Name("MusicFinished"), object: nil)// 監聽通知
NotificationCenter.default.addObserver(self, selector: #selector(musicFinished), name: NSNotification.Name("MusicFinished"), object: nil)@objc func musicFinished() {print("播放完成")
}

4. swift_event_bus(事件總線)

? ? 適用場景:適用于 一對多多對多 事件傳遞,通常用于解耦模塊間的通信。

? ? 實現方式:通過 SwiftEventBus 發布和訂閱事件。

? ? 特點

? ? 類似 NotificationCenter,但更輕量級,支持異步和線程調度。

? ? 適用于模塊化架構,如 MVVM、VIPER。

? ? 易用性比 NotificationCenter 更高,但不如 delegate 和 closure 類型安全。

代碼示例:

import SwiftEventBus// 訂閱事件
SwiftEventBus.onMainThread(self, name: "MusicFinished") { result inprint("播放完成")
}// 發送事件
SwiftEventBus.post("MusicFinished")

總結對比

方式適用場景關系類型適用范圍代碼復雜度解耦性
代理(Delegate)長期一對一通信一對一UI 組件、數據回調
閉包(Closure)短期回調一對一異步任務、臨時事件
Notification一對多通信一對多全局事件、廣播
swift_event_bus模塊間解耦一對多/多對多事件驅動架構

選擇建議

? ? 一對一且長期的關系(如 UITableView)→ Delegate

? ? 一對一且是短期任務(如異步回調)→ Closure

? ? 一對多或全局事件(如 App 生命周期)→ NotificationCenter

? ? 解耦多個模塊的通信(如 MVVM)→ swift_event_bus

你目前的 myMusic 項目如果涉及 UI 組件間的通信,比如播放器狀態更新,建議:

? ? 使用 Delegate 處理播放器的狀態回調。

? ? 使用 Closure 處理網絡請求回調。

? ? 使用 NotificationCenter 或 swift_event_bus 處理全局事件(如登錄成功、歌曲切換)。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/897878.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/897878.shtml
英文地址,請注明出處:http://en.pswp.cn/news/897878.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

設計模式--單例模式(Singleton)【Go】

引言 在設計模式中,單例模式(Singleton Pattern)是一種非常常見且實用的模式。它的核心思想是確保一個類只有一個實例,并提供一個全局訪問點。這種模式在需要全局唯一對象的場景中非常有用,比如配置管理、日志記錄、數…

MySQL數據庫復制

文章目錄 MySQL數據庫復制一、復制的原理二、復制的搭建1.編輯配置文件2.在主庫上創建復制的用戶3.獲取主庫的備份4.基于從庫的恢復5.建立主從復制6.開啟主從復制7.查看主從復制狀態 MySQL數據庫復制 MySQL作為非常流行的數據庫,支撐它如此出彩的因素主要有兩個&am…

Sourcetree——使用.gitignore忽略文件或者文件夾

一、為何需要文件忽略機制? 1.1 為什么要會略? 對于開發者而言,明智地選擇忽略某些文件類型,能帶來三大核心優勢: 倉庫純凈性:避免二進制文件、編譯產物等污染代碼庫 安全防護:防止敏感信息&…

基于yolov8+streamlit實現目標檢測系統帶漂亮登錄界面

【項目介紹】 基于YOLOv8和Streamlit實現的目標檢測系統,結合了YOLOv8先進的目標檢測能力與Streamlit快速構建交互式Web應用的優勢,為用戶提供了一個功能強大且操作簡便的目標檢測平臺。該系統不僅具備高精度的目標檢測功能,還擁有一個漂亮且…

分享vue好用的pdf 工具實測

vue3-pdf-app: 帶大綱,帶分頁,帶縮放,帶全屏,帶打印,帶下載,帶旋轉 下載依賴: yarn add vue3-pdf-appornpm install vue3-pdf-app 配置類: 創建文件 pdfConfig.ts /…

基于微信小程序開發的寵物領養平臺——代碼解讀

項目前端 一、項目的技術架構概況 一句話概括:該項目是基于微信小程序開發的寵物領養平臺,采用原生小程序框架進行用戶界面的構建,使用 wx.request 進行 API 請求,并通過 getApp() 和本地存儲來管理全局狀態和用戶信息。 一&am…

最完美的WPF無邊框設計!

常規的無邊框方法設計 常規的WPF無邊框設計方法都是通過AllowsTransparency="True"和WindowStyle=“None”,并且使用WindowChrome樣式來實現,但是這樣會有問題就是,窗體最大化的時候將底部任務欄給擋住了,另外最大化的時候不能拖動窗體。參考這個大佬的設計@ 若…

【區塊鏈】btc

學習視頻源鏈接: https://www.bilibili.com/video/BV1Vt411X7JF/ 本文是根據肖老師的視頻進行的筆記記錄 一、 cryptographic hash function 1.1. collision resistance抗碰撞性 : collision 指的是hash碰撞 抗碰撞性 (Collision Resistance) 是密碼…

C語言【數據結構】:時間復雜度和空間復雜度.詳解

引言 詳細介紹什么是時間復雜度和空間復雜度。 前言:為什么要學習時間復雜度和空間復雜度 算法在編寫成可執行程序后,運行時需要耗費時間資源和空間(內存)資源。因此衡量一個算法的好壞,一般是從時間和空間兩個維度來衡量的,即時…

QT:文件讀取

問題: 在文件讀取,判斷md5值時,遇到py文件讀取轉String后,再轉byte,md5前后不一致問題。 解決方法: python文件讀取要使用QTextStream,避免\t 、\r、\n的換行符跨平臺問題(window…

32單片機——LED

LED原理圖如圖所示: 代碼 DS0和DS1每過500ms一次交替閃爍,實現類似跑馬燈的效果 GPIO輸出配置步驟 (1)使能對應GPIO時鐘 STM32在使用任何外設之前,我們都要先使能其時鐘(下同)。本實驗用到…

貪心算法和遺傳算法優劣對比——c#

項目背景:某鋼管廠的鋼筋原材料為 55米,工作需要需切割 40 米(1段)、11 米(15 段)等 4 種規格 ,現用貪心算法和遺傳算法兩種算法進行計算: 第一局:{ 40, 1 }, { 11, 15…

【Java篇】一法不變,萬象歸一:方法封裝與遞歸的思想之道

文章目錄 Java 方法的使用:從基礎到遞歸的全面解析一、方法的概念及使用1.1 什么是方法 (method)?1.2 方法定義1.3 方法調用的執行過程1.4 實參和形參的關系1.5 沒有返回值的方法 二、方法重載2.1 為什么需要方法重載2.2 方法重載的概念2.2.4 C 和 Java 的比較&…

深入理解 HTML 中的<div>和元素:構建網頁結構與樣式的基石

一、引言 在 HTML 的世界里&#xff0c;<div>和元素雖看似普通&#xff0c;卻扮演著極為關鍵的角色。它們就像網頁搭建過程中的萬能積木&#xff0c;能夠將各種 HTML 元素巧妙地組合起來&#xff0c;無論是構建頁面布局&#xff0c;還是對局部內容進行樣式調整&#xff…

《大語言模型》學習筆記(一)

一、什么是大語言模型 大語言模型是指在海量無標注文本數據上進行預訓練得到的大型預訓練語言模型&#xff0c;例如GPT-3&#xff0c;PaLM和LLaMA。大語言模型&#xff08;Large Language Model&#xff0c;LLM&#xff09;是一種基于深度學習的自然語言處理模型&#xff0c;能…

電力行業中分布式能源管理(Distributed Energy Management System, DEMS)的實現

以下是電力行業中分布式能源管理(Distributed Energy Management System, DEMS)的實現方案,涵蓋系統架構、關鍵技術、核心功能及實施路徑,結合典型場景與代碼示例: 一、系統架構設計 采用云-邊-端三層架構,實現分布式能源的高效協同管理: 1. 終端層(感知層) 設備組…

實驗5 邏輯回歸

實驗5 邏輯回歸 【實驗目的】掌握邏輯回歸算法 【實驗內容】處理樣本&#xff0c;使用邏輯回歸算法進行參數估計&#xff0c;并畫出分類邊界 【實驗要求】寫明實驗步驟&#xff0c;必要時補充截圖 1、參照“2.1梯度下降法實現線性邏輯回歸.ipynb”和“2.2 sklearn實現線性邏輯…

思維訓練讓你更高、更強 |【邏輯思維能力】「刷題訓練筆記」假設法模式邏輯訓練題(1-5)

每日一刷 思維訓練讓你更高、更強&#xff01; 題目1 誰在說謊&#xff0c;誰拿走了零錢&#xff1f; 姐姐上街買菜回來后&#xff0c;就隨手把手里的一些零錢放在了抽屜里&#xff0c;可是&#xff0c;等姐姐下午再去拿錢買菜的時候發現抽屜里的零錢沒有了&#xff0c;于是&…

【愚公系列】《高效使用DeepSeek》004-DeepSeek的產品形態和功能詳解

標題詳情作者簡介愚公搬代碼頭銜華為云特約編輯,華為云云享專家,華為開發者專家,華為產品云測專家,CSDN博客專家,CSDN商業化專家,阿里云專家博主,阿里云簽約作者,騰訊云優秀博主,騰訊云內容共創官,掘金優秀博主,亞馬遜技領云博主,51CTO博客專家等。近期榮譽2022年度…

用python代碼將excel中的數據批量寫入Json中的某個字段,生成新的Json文件

需求 需求&#xff1a; 1.將execl文件中的A列賦值給json中的TrackId&#xff0c;B列賦值給json中的OId 要求 execl的每一行&#xff0c;對應json中的每一個OId json 如下&#xff1a; {"List": [{"BatchNumber": "181-{{var}}",// "Bat…