import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//閉包引起的循環強引用
//循環強引用還會發生在當你將一個閉包賦值給類實例的某個屬性,並且這個閉包體中又使用了這個類實例。這個閉包體中可能訪問了實例的某個屬性,例如self.someProperty,或者閉包中調用了實例的某個方法,例如self.someMethod.這兩種情況都導致了閉包捕獲self,從而產生循環強引用
//循環引用的產生,是因爲閉包和類相似,都是引用類型。當你把一個引用賦值給了閉包。實質上,這兩個強引用讓彼此一直有效。但是和兩個類實例不同的是一個是類實例另一個是閉包。
var paragraph:HTMLElement?=HTMLElement(name: "P", text: "hello world")
print(paragraph!.asHTML())//P hello world P
//HTMLElement類產生了類實例和asHTML默認值的閉包之間的循環強引用
/*
{
if let text = self.text {
return "\(self.name) \(text) \(self.name)"
}else{
return "\(self.name)"
}
}該閉包引用了self即強引用了HTMLElement實例,
lazy var asHTML: Void->String該變量又強引用了閉包
*/
paragraph=nil //不會觸發deinit析構函數
//解決閉包引起的循環強引用
//在定義閉包時同時定義捕獲列表作爲閉包的一部分,通過這種方式可以解決閉包和類實例之間的循環強引用。捕獲列表定義了閉包體內捕獲一個或者多個引用類型的規則
//捕獲列表中的每一項都由一對元素組成,一個元素是weak或unowned關鍵字,另一個元素是類實例的引用。這些項在方括號中用逗號分開
//如果閉包有參數列表和返回類型,把捕獲列表放在它們前面
var paragraph2:HTMLElement?=HTMLElement(name: "P", text: "hello world")
print(paragraph2!.asHTML2())//P hello world P
//P is being deinit
//注意:如果被捕獲的引用絕對不會變爲nil,應該用無主引用,而不是弱引用,弱引用總是可選類型,並且當引用的實例被銷燬後,弱引用的值會自動置爲nil。
}
}
class HTMLElement{
lazy var asHTML2: Void->String = {
[unowned self] in //用無主引用而不是強引用來捕獲self
if let text = self.text {
return "\(self.name) \(text) \(self.name)"
}else{
return "\(self.name)"
}
}
let name:String
let text:String?
lazy var asHTML: Void->String = {
if let text = self.text {
return "\(self.name) \(text) \(self.name)"
}else{
return "\(self.name)"
}
}
init(name:String,text:String?=nil){
self.name=name;
self.text=text;
}
deinit{
print("\(name) is being deinit")
}
}
//lazy var someClosure: Void -> String = {
// [unowned self, weak delegate = self.delegate!] in
// // closure body goes here
//}