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
//}