Swift中的循环引用是怎么样的呢?我们来看看:
func loadData(completion:@escaping ()->()) -> () {
//异步
DispatchQueue.global().async {
print("耗时操作")
DispatchQueue.main.async {
//回调,执行闭包
completion()
}
}
}
//类似于oc的dealloc
deinit {
print("我去了")
}
调用:
loadData {
print(self.view)
}
这样是不会引起循环引用的,为什么呢?
//block中如果出现self.要特别小心
//循环引用单方向对引用是不会产生循环引用
//只是闭包对self.进行了copy,闭包执行完成之后,会自动销毁,同时释放对self引用
要循环引用还要self
对闭包引用:
所以循环引用是下面这样的:
func loadData(completion:@escaping ()->()) -> () {
//使用属性记录闭包 -> self对闭包引用了
completionCallBack = completion
//异步
DispatchQueue.global().async {
print("耗时操作")
Thread.sleep(forTimeInterval: 2.0)
DispatchQueue.main.async {
//回调,执行闭包
completion()
}
}
}
//类似于oc的dealloc
deinit {
print("我去了")
}
调用:
class ViewController: UIViewController {
//属性就是一个var
var completionCallBack: (()->())?
override func viewDidLoad() {
super.viewDidLoad()
print(self.view)
}
这样就形成了循环引用,我们可以在sb中加个nav测试一下,deinit
就不会打印。
循环引用就是一个环, 我引用你,你引用我,所以就会形成循环引用,要解除循环引用,就需要打断链条,有三种方法,第一种是用OC的方式如下:
//方法一:用OC的方式
//细节一 var weak只能修饰var 不能修饰let
//'weak' must be a mutable variable, because it may change at runtime
//weak可能会被在运行时被修改 -> 指向的对象被释放会被自动设置为nil
weak var weakSelf = self;
loadData {
//细节二
//解包有两种方式解包
//? 可选解包 -如果self已经被释放,不会向对象发送getter的消息,更加安全
//!强行解包 -如果self已经被释放,强行解包会导致崩溃
/**
weakSelf?.view 只是单纯的发送消息,没有计算
强行解包 因为需要计算 可选项不能直接参与到计算
*/
print(weakSelf?.view as Any)
}
方法二,使用swift推荐的方法:
//方法二:swfit的推荐方法
//[weak self]表示{}中的所有self都是弱引用,需要注意解包
loadData { [weak self] in
print(self?.view as Any)
}
方法三:
//方法三:swfit的另外一个方法 知道就好
//[unowned self]表示{}中的所有slef都是assign的,不会强引用,但是。如果释放,指针地址不会变化
//如果对象被释放,继续调用就会出现野指针的问题
loadData { [unowned self] in
print(self.view as Any)
}
循环引用的解决办法推荐使用第一种和第二种方法。