这个是非常常见的一个问题,你可以从这里获取我们的演示 Demo
例如我们创建了一个 BadGuy() 功能只有一个,可以存一个闭包。
class BadGuy: NSObject { var holdAction: (() -> Void)? }
然后我们从外层 ViewController 通过 Push 的方法进入 DetailViewController,DetailViewController 里创建了 10000 个 UIView 来占用些内存,badGuy 通过闭包修改了下 DetailViewController 的 hello 的属性。
import UIKit class 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 = 10000 while a > 0 { a -= 1 view.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 UIKit class 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] in self?.hello = "Hello" } var a = 10000 while a > 0 { a -= 1 view.addSubview(UIView()) } } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } deinit { print("Deinit") } }
做了这样的修改后,反复进行返回,进入的测试,也不会导致内存暴增了,deinit 也会在你返回的时候成功打印。
你的 App 是否有这个问题呢?