循环引用
这个是非常常见的一个问题,你可以从这里获取我们的演示 Demo
例如我们创建了一个 BadGuy() 功能只有一个,可以存一个闭包。
class BadGuy: NSObject { var holdAction: (() -> Void)?}
然后我们从外层 ViewController 通过 Push 的方法进入 DetailViewController,DetailViewController 里创建了 10000 个 UIView 来占用些内存,badGuy 通过闭包修改了下 DetailViewController 的 hello 的属性。
import UIKitclass DetailViewController: UIViewController {var badGuy = BadGuy()var hello: String?override func viewDidLoad() {super.viewDidLoad()// Do any additional setup after loading the view, typically from a nib.badGuy.holdAction = {self.hello = "Hello"}var a = 10000while a > 0 {a -= 1view.addSubview(UIView())}}override func didReceiveMemoryWarning() {super.didReceiveMemoryWarning()// Dispose of any resources that can be recreated.}deinit {print("Deinit")}}
在 push 前内存占用是 20M, push 后内存占用为 32.3M 反复进行几次后,内存占用会不停往上飙升,deinit 方法的打印也不会执行。
原因
holdAction 这个闭包引用了 DetailViewController 的 hello,而这个 self.hello 又因为强引用 DetailViewController 的原因,导致当你返回的时候,DetailViewController 并不会被释放。
强引用
只要有任何对象强引用对象 A,ARC 就不会摧毁 A。
弱引用
弱引用对象 B 的情况下,若没有其他物体强引用对象 B,ARC 会摧毁 B。
解药
在 GoodViewController 里我们可以通过更改强引用为弱引用的方法,来避免这种情况。
import UIKitclass GoodViewController: UIViewController {var badGuy = BadGuy()var hello: String?override func viewDidLoad() {super.viewDidLoad()// Do any additional setup after loading the view, typically from a nib.badGuy.holdAction = { [weak self] inself?.hello = "Hello"}var a = 10000while a > 0 {a -= 1view.addSubview(UIView())}}override func didReceiveMemoryWarning() {super.didReceiveMemoryWarning()// Dispose of any resources that can be recreated.}deinit {print("Deinit")}}
做了这样的修改后,反复进行返回,进入的测试,也不会导致内存暴增了,deinit 也会在你返回的时候成功打印。
你的 App 是否有这个问题呢?