Swift中如何避免迴圈引用的方法

2022-09-20 21:30:12 字數 3466 閱讀 8061

記憶體管理中經常會遇到的乙個問題便是迴圈引用。首先,我們來了解一下ios是如何進行記憶體管理的。

和oc一樣,swift也是使用自動引用計數arc(auto reference counteting)來自動管理記憶體的,所以我們不需要過多考慮記憶體管理.當某個類例項不需要用到的時候,arc會自動釋放其占用的記憶體.

arcarc(automatic reference counting) 是蘋果的自動記憶體管理機制。正如其名:自動引用計數,根據引用計數來決定記憶體塊是否應該被釋放。

當乙個物件被建立的時候,它的引用計數為1。在它的生命週期內,其引用計數可以增加或減少。當它的引用計數減為0的時候,其www.cppcns.com所占用記憶體便會被釋放。其生命週期如圖所示:

強引用和弱引用(strong/weak references)

定義乙個變數的時候可以宣告其strong和weak屬性,預設是strong型別。

struct example

強引用和弱引用有什麼不同呢?

強引用會使變數的引用計數加1。如果乙個物件的引用計數為2,當它再次被強引用的時候,它的引用計數會變為3。

弱引用不會增加引用計數。如果乙個物件的引用計數為2,當它再次被弱引用的時候,它的引用計數仍為2。

強引用的物件能保證其被呼叫的時候仍在記憶體中,而弱引用不行。

迴圈引用和記憶體洩漏

當a引用b中的成員變數,而b又對a中的成員變數有引用的時候就會發生迴圈引用。

比如:class book

}class page

}let book = book()

let page = page(book: book)

book.add(page)

此時,book對page有強引用,同時page對book也有強引用。這個時候便有迴圈引用,會導致記憶體洩漏。

對於這種兩個變數的相互強引用導致的記憶體洩漏該如何解決呢?

structs 和 classes

正確的使用struct 和 class能避免迴圈引用的發生。

struct 和 class 都有成員變數,函式和協議。那麼,它們之間有什麼區別呢?

struct 是 值型別。

class 是 引用型別。

當引用或者傳遞 值型別 變數的時候,它會在記憶體中重新分配位址,copy內容到新的位址中。

struct element

var firstelement = element(name: "a", number: 1)

程式設計客棧

var secondelement = firstelement

secondelement.name = "b"

secondelement.number = 2

print(firstelement)

print(secondelement)

輸出的結果為:

element(name: 「a」, number: 1)

element(name: 「b」, number: 2)

當引用或者傳遞 引用型別 變數的時候,新的變數指標指向的仍是原先的記憶體位址。此時原先的變數值改變的話,也會導致新變數值的變化。

比如:class element

}extension element : customstringconvertible

}var firstelement = element(name: "a", number: 1)

var secondelement = firstelement

secondelement.name = "b"

secondelement.number = 2

print(firstelement)

print(secondelement)

此時的輸出結果為:

element(name: b, number: 2)

element(name: b, number: 2)

我們為什麼在此討論值型別和引用型別呢?

回到之前book和pages的例子。我們用struct代替class:

struct book

}struct page

}var book = book()

let page = page(book:jkddblhwf book)

book.add(page)

此時,便不會發生迴圈引用的情況。

如果仍想使用class的話,可以使用weak來避免迴圈引程式設計客棧用:

class book

}class page

}let book = book()

let page = page(book: book)

book.add(page)

protocols

protocols在swift中使用的很廣泛。class,struct 和 enum 都可以使用protocol。但是如果使用不當的話,同樣會引起迴圈引用。

比如:protocol listviewcontrollerdelegate

class listviewcontroller : uiviewcontroller

}listviewcontroller 中的delegate變數是strong型別的,可以引用任何實現它proto程式設計客棧col的變數。假如實現其protocol的變數對該 view controller 同樣有強引用的話會怎麼樣? 宣告delegate為weak可能會避免這種情況,但是這樣的話會引起編譯錯誤,因為structs和enums不能引用weak變數。

該如何解決呢?當宣告protocol的時候,我們可以指定只有class型別的變數可以**它,這樣的話就可以使用weak來修飾了。

protocol listviewcontrollerdelegate : class

class listviewcontroller : uiviewcontroller

}closures

closures 導致迴圈引用的原因是:closures對使用它們的物件有乙個強引用。

比如:class example

init() }

func foo()

}此時,物件對closure有乙個強引用,同時在closure的**塊中又對該物件本身有乙個強引用。這樣就引起了迴圈引用的發生。

這種情況,可以有兩種方法來解決這個問題。

1.使用[unowned self]:

class example

init() }

func foo()

}使用[unowned self] 的時候需要注意的一點是:呼叫closure的時候如果物件已經被釋放的話,會出現crash。

2.使用[weak self]:

class example

init() }

func foo()

}[weak self] 和[unowned self] 的區別是 [weak self]處理的時候是乙個可選型別。

本文標題: swift中如何避免迴圈引用的方法

本文位址:

Swift 迴圈引用

要解決閉包引起的迴圈引用,swift 中引入了 捕獲列表 的概念,在閉包的引數列表中將閉包體中涉及的所有被 持有 物件宣告為 無主引用 或者 弱引用 以逗號隔開。將閉包作為類的屬性是一種非常常見的做法,相比於定義乙個方法,定義乙個閉包型別的屬性可以隨時修改閉包中的執行內容,以此達到復用的效果,減少乙...

Swift 排查引用迴圈

恢復內容開始 一 最近使用rxswift在多次訊號的巢狀中,發現乙個物件始終始終無法釋放 開始想通過memory graph驗證是否沒有釋放,一直報錯,後來確認是xcode的bug 始終無法確認問題,只能考慮使用乙個弱引用的陣列來驗證了 final class weakbox 類定義 private...

打破 Swift 結構體中的迴圈引用

本文講的是打破 swift 結構體中的迴圈引用,嘗試從乙個閉包中訪問結構體 瘋狂的迴圈 我們要怎樣破解這個迴圈?複製行不通,共享引用怎麼樣?一些觀點 說在最後 final class ondelete deinit deletionlogger do deletionlogger deleted 嘗...