Delegated - 自動實現閉包的 weak self

Delegated - 自動 weak self

Closure,在平常代碼中會常常使用到。使用它時,爲了防止可惡的內存泄漏,要時常記得寫 [weak self] 這樣的代碼。但對於程序員來講寫這種模板代碼是很枯燥的,因此, Delegated 就應運而生了。經過它註冊事後的 Closure,能夠自動的 weak self。下面就來看一下它的基本使用吧。git

基本使用

它的使用很簡單,經過下面兩個步驟就能夠實現自動的 weak self:程序員

  • 使用 @Delegated 聲明 Closure。
  • 使用 delegate() 函數來調用 Closure。

來看一個具體的例子: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

  • Delegated0:對應無返回值,無參數的 Closure。
  • Delegated1:對應無返回值,一個參數的 Closure。
  • Delegated2:對應無返回值,兩個參數的 Closure。
  • Delegated3:對應無返回值,三個參數的 Closure。
  • ReturningDelegated0:對應有返回值,無參數的 Closure。
  • ReturningDelegated1:對應有返回值,一個參數的 Closure。
  • ReturningDelegated2:對應有返回值,兩個參數的 Closure。
  • ReturningDelegated3:對應有返回值,三個參數的 Closure。

雖然代碼包含上面 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 函數接受兩個參數:

  • target:須要 weak 的對象。
  • callback:實際用到的 closure。

能夠看到,在 delegate 函數體內,就是自動 weak self 的關鍵部分。對 callback 進行了從新賦值:

self.callback = { [weak target] input in
    // 經過這裏實現自動 weak self
    guard let target = target else {
        return
    }
    return callback(target, input)
}
複製代碼

extension 中還有兩個函數,它們的代碼也很好理解:

  • manuallyDelegate:手動管理,即不使用自動 weak self。經過代碼也能夠看出它是直接給 callback 賦值,沒有進行上面的 weak self 操做。
  • removeDelegate:移除代理。

至此,源碼就分析完了。能夠看到這個庫的代碼仍是很是短小精悍的。

總結

  • 經過 @propertyWrapper 來進行模板代碼封裝。
  • 經過 callback 的從新賦值來實現自動 weak self。
相關文章
相關標籤/搜索