1.什么是循環(huán)引用
兩個對象通過屬性互相強引用對方,導致無法正常釋放
情境代碼
class City{
var country : Country?
deinit{
print("city is deinit")
}
}
class Country {
var capital : City?
deinit{
print("country is deinit")
}
}
不會循環(huán)引用
var city:City? = City()
var country:Country? = Country()
city!.country = country!
city = nil
country = nil
//city country此時釋放會正常打印
//city is deinit
//country is deinit
會導致循環(huán)引用
var city2:City? = City()
var country2:Country? = Country()
city2!.country = country2!
country2!.capital=city2!
city2 = nil
country2 = nil
//city country此時設為nil,沒有任何打印,說明并不會正常釋放

兩個強指針指向?qū)Ψ綄е禄ハ酂o法釋放
2.在optional類型的屬性中加上weak關鍵字
weak關鍵詞不會使引用計數(shù)+1,同時如果所指向?qū)ο蟊会尫?,則自動設為nil
class City2{
weak var country : Country2?
deinit{
print("city2 is deinit")
}
}
class Country2 {
var capital : City2?
deinit{
print("country2 is deinit")
}
}
var city2:City2? = City2()
var country2:Country2? = Country2()
country2?.capital=city2!
city2?.country=country2
city2?.country == nil //false
country2 = nil //打印 country is deinit
city2?.country == nil //true
city2 = nil //打印 city2 is deinit

有一方為weak類型屬性的示意圖
3.在非optional類型的屬性中加上unown關鍵字
unown關鍵字只是不會使引用計數(shù)+1,所指向的對象被釋放后,此屬性不能再被訪問,否則會報錯
class City3{
var country : Country3?
deinit{
print("city3 is deinit")
}
}
class Country3 {
unowned var capital : City3
init(capital:City3){
self.capital = capital;
}
deinit{
print("country3 is deinit")
}
}
var city3:City3? = City3()
var country3:Country3? = Country3(capital:city3!)
city3?.country=country3
//打印 city2 is deinit
country3?.capital == nil //false
city3 = nil //打印 city3 is deinit
//country3?.capital == nil //報錯
country3 = nil //打印 country3 is deinit

有一方為unowned類型屬性的示意圖
所以應該根據(jù)實際情況來決定是使用unowned關鍵字還是weak關鍵字
4.closure中的循環(huán)引用
class HTMLElement{
var text:String
init(text:String){
self.text=text
}
lazy var asHTML : Void -> String = {
return "<text>\(self.text)</text>"
}
deinit{
print("HTMLElement 被 釋放了")
}
}
看起來并沒有什么問題,編譯器也沒有報錯
但是
var e :HTMLElement? = HTMLElement(text:"haha")
e?.asHTML()
e = nil //并沒有任何打印,說明發(fā)生了循環(huán)引用
為什么會發(fā)生循環(huán)引用?
因為closure實際上也是一個對象,并且會捕獲其所用到的變量。并默認使用一個強類型的指針,指向其用到的變量。這里發(fā)生的情況,如圖

HTMLElement與Closure循環(huán)引用示意圖
那么如何將其中的一個強類型指針改變成weak或者unowned呢?改變asHTML屬性的類型為weak或者unowned嗎?
顯然不行,weak 和 unowned 只適用于class和protocol類型的屬性
那只有修改closure中self的指針類型了
這樣,在closure中加上[unowned self]的說明
class HTMLElement{
var text:String
init(text:String){
self.text=text
}
lazy var asHTML : Void -> String = { [unowned self] in
return "<text>\(self.text)</text>"
}
deinit{
print("HTMLElement 被 釋放了")
}
}
如果是多個說明的話用逗號隔開比如
[unowned self,weak other]
這個說明應該放在參數(shù)列表的前面
lazy var asHTML : Void -> String = { [unowned self] () -> String in
return "<text>\(self.text)</text>"
}
加上說明再來測試一下
var e :HTMLElement? = HTMLElement(text:"haha")
e?.asHTML()
e = nil //打印HTMLElement 被 釋放了
說明正常釋放了