在我們前幾天的學習中,已經認識了 struct 結構體、class 類別,還有能幫我們擴充功能的 extension。
今天,我們要讓這些工具之間「互相交流」,也就是要學 delegate(委派) 與 protocol(協議)!
protocol
可以想像成「規格書」或「合約」——它不會告訴你怎麼做,但會告訴你必須「會做什麼」。
任何 class
、struct
、enum
只要「簽了這份合約」,就必須實作裡面要求的功能。
protocol 協議名稱 {
// 方法
func 做某件事()
// 屬性(可以讀寫或唯讀)
var 名稱: String { get set }
}
protocol FruitDelivery {
func deliverFruit(name: String)
}
struct AppleStore: FruitDelivery {
func deliverFruit(name: String) {
print("送出一箱 \(name) ")
}
}
struct BananaStore: FruitDelivery {
func deliverFruit(name: String) {
print("送出一串 \(name) ")
}
}
let appleShop = AppleStore()
appleShop.deliverFruit(name: "富士蘋果")
let bananaShop = BananaStore()
bananaShop.deliverFruit(name: "金香蕉")
🔍 解說
FruitDelivery
是協議protocol
。AppleStore
和 BananaStore
都遵守它,所以都必須有 deliverFruit
這個方法。delegate
是一種「設計模式」,用來把某件事「交給別人做」,而這個「別人」就是代理人(delegate)。
這樣可以讓不同物件之間互相溝通,而不用緊密綁死彼此的程式碼。
protocol 協議名稱: AnyObject { // 限制只能給 class 用
func 要代理做的事()
}
class 發送方 {
weak var delegate: 協議名稱? // 防止循環引用
}
protocol DeliveryDelegate: AnyObject {
func sendBanana(to place: String)
}
class AppleStore {
//別忘記要設delegate變數!
weak var delegate: DeliveryDelegate?
func orderBanana() {
print("AppleStore:我需要香蕉")
delegate?.sendBanana(to: "蘋果商店")
}
}
class BananaStore: DeliveryDelegate {
func sendBanana(to place: String) {
print("BananaStore:香蕉已送到 \(place)!")
}
}
let appleStore = AppleStore()
let bananaStore = BananaStore()
appleStore.delegate = bananaStore
appleStore.orderBanana()
解說
DeliveryDelegate
是規範代理人必須會做的事(送香蕉)。AppleStore
有一個 delegate
屬性,可以指派給任何遵守這個協議的物件。BananaStore
符合 DeliveryDelegate
,所以可以被指派成代理人。AppleStore
呼叫 delegate?.sendBanana
,實際上是由 BananaStore
幫它送香蕉。當一個物件自己遵守協議並擔任自己的代理人時,可以直接用 self
來指定:
appleStore.delegate = self
這樣代表「我自己就是我的代理人」,不過通常會用在 UIViewController
內部,讓自己處理某些回呼事件。
self
在 delegate 中常用來表示「我自己就是代理人」。學會這個概念之後,你就能在 App 中建立物件和介面間的溝通橋樑,讓程式更靈活、更好維護!