簡體   English   中英

Swift-在基於閉包的配置中避免強大的參考周期

[英]Swift - Avoiding strong reference cycles in closure-based configuration

請注意:我已經閱讀了很多(非常多)的答案和文章,這些主題都是關於避免強參考周期的。 但是,我正在尋找有關如何處理避免這些周期的特定副產品的指南。

在以下示例中,將類Foo設計為使用閉包進行配置。 緩存對閉包的引用以供以后使用。

每當需要Model數據時,都會調用該閉包。 為了使Foo正常工作,數據必須存在。

class Foo
{
    typealias ModelGetter = (() -> Model)
    fileprivate var _modelGetter: ModelGetter!

    ...

    func configure(with modelGetter: @escaping ModalGetter)
    {
        _modelGetter = modelGetter
    }

    func printLastestModel()
    {
        // Get the latest model, do something with it.
        precondition(_modelGetter != nil)
        let model = _modelGetter()
        print(model)
    }
}

在上面的代碼中,_modelGetter被隱式展開。 盡管我可以將其定義為Optional ,並根據需要對其進行解包,但是Foo始終需要設置閉包才能正常工作,因此需要進行隱式解包。

制作Foo實例並進行配置:

let foo = Foo()
foo.configure(with: { self.makeModel() })
foo.printLatestModel()

但是,這創建了一個保留周期。

因此,使用[weak self] ,我們檢查self的可選性:

foo.configure(with: { [weak self] in
    guard let strongSelf = self else { return **WHAT** }
    return strongSelf.makeModel()
})

問題

這要求即使self可能為nil,閉包仍然需要向閉包的調用者(Foo實例)返回一個Model(即WHAT?)。但是,由於self為nil,因此我沒有Model交出。

有人可以推薦在這種情況下使用的模式嗎? 最好,我不希望Foo檢查modelGetter是否有效,或者不知道Model是否有效。 出於Foo的目的,如果Foo存在,那么它必須始終能夠獲得所需的模型。

或者,我是否應該重新設計Foo的需求,以考慮到無法購買模型的可能性? 感謝您的任何幫助。

如果Class是Foo的所有者,建議設置[unowned self]而不是[weak self] 它將解決問題。 如果一個類是另一個類的所有者,它將永遠不會出現問題,但如果邏輯錯誤,它將出現崩潰。 這還不錯,因為它向您發出信號,表明您在項目中破壞了某些內容。

但是,這創建了一個保留周期。

不,不是。 foo擁有對閉包的引用,而閉包擁有對self的引用(顯然不是foo )。 如果您self具有Foo類型的強屬性並將其設置為foo ,則只會得到一個保留周期。

假設您將要這樣做,我將使用以下兩種模式之一:

  • 我以程序員的身份假設,在foo整個生命周期中, self永遠都會存在。 在那種情況下,我將使用[unowned self]而不是[weak self] 如果我的假設被證明是錯誤的,程序將中止,並且我將能夠基於堆棧跟蹤來修復該錯誤。 顯然,您將需要一個相當廣泛的測試套件來盡可能地驗證假設。

  • 我認為self消失是有效的,在這種情況下,您對如何處理消失有三種選擇:

    • 使閉包的返回類型為可選,即() -> Model? 並使Foo能夠處理nil模型
    • 如果selfnil ,則返回一個默認Model
    • 使閉包聲明它拋出並在selfnil拋出錯誤。

我想我可能會選擇[unowned self] ,並確保我在某處明確引用了它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM