Closure,在平常代碼中會常常使用到。使用它時,爲了防止可惡的內存泄漏,要時常記得寫 [weak self]
這樣的代碼。但對於程序員來講寫這種模板代碼是很枯燥的,因此, Delegated 就應運而生了。經過它註冊事後的 Closure,能夠自動的 weak self。下面就來看一下它的基本使用吧。git
它的使用很簡單,經過下面兩個步驟就能夠實現自動的 weak self:程序員
來看一個具體的例子:github
final class TextField {
// 第一步:使用 @Delegated 聲明 Closure。
@Delegated var didUpdate: (String) -> ()
}
// 第二步:使用 delegate() 函數來調用 Closure。
textField.$didUpdate.delegate(to: self) { (self, text) in
// `self` is weak automatically!
self.label.text = text
}
複製代碼
經過上面的兩步就實現了自動 weak self,沒有循環引用,沒有內存泄漏,沒有 [weak self]
!🎉swift
掌握了它的使用方法以後,下面來看一下它的實現原理。它的代碼很簡單,只有一個 Delegated.swift 文件,代碼只有 410 行。api
全部類的說明:markdown
雖然代碼包含上面 8 個類,但實質上只要理解了其中的任意一個類便可,由於其餘的類只是參數和有無返回值的不一樣而已。app
在這裏,拿 Delegated1 來舉例說明一下它的實現原理。函數
@propertyWrapper
public final class Delegated1<Input> {
public init() { self.callback = { _ in } }
private var callback: (Input) -> Void
public var wrappedValue: (Input) -> Void { return callback }
public var projectedValue: Delegated1<Input> {
return self
}
}
public extension Delegated1 {
func delegate<Target: AnyObject>(
to target: Target,
with callback: @escaping (Target, Input) -> Void
) {
self.callback = { [weak target] input in
guard let target = target else {
return
}
return callback(target, input)
}
}
func manuallyDelegate(with callback: @escaping (Input) -> Void) {
self.callback = callback
}
func removeDelegate() {
self.callback = { _ in }
}
}
複製代碼
首先,來分析一下 Delegated1 類。能夠看到它使用了 @propertyWrapper 關鍵字來修飾,@propertyWrapper 的做用簡單來講就是用來封裝日常的模板代碼。關於@propertyWrapper更詳細的介紹能夠看這裏。oop
接着,它經過定義 Input 來實現參數支持泛型,而後聲明瞭 callback 屬性來存儲 Closure。對於 wrappedValue 和 projectedValue 則是重寫的 @propertyWrapper 的內置參數。spa
接着,來看一下 extension 中的 delegate 函數。delegate 函數接受兩個參數:
能夠看到,在 delegate 函數體內,就是自動 weak self 的關鍵部分。對 callback 進行了從新賦值:
self.callback = { [weak target] input in
// 經過這裏實現自動 weak self
guard let target = target else {
return
}
return callback(target, input)
}
複製代碼
extension 中還有兩個函數,它們的代碼也很好理解:
至此,源碼就分析完了。能夠看到這個庫的代碼仍是很是短小精悍的。