Demo 下载
先来看一段代码
import UIKit
class SecViewController: UIViewController {
var index: Int = 0
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .white
// Do any additional setup after loading the view.
Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(log), userInfo: nil, repeats: true)
}
@objc func log() {
index += 1
print("定时器在作用----\(index)")
}
}
当 SecVewiController pop之后 定时器仍然在工作
这种情况显然不是我们想要的, 我们想要的结果是 当前 vc pop 之后定时器也自动销毁
很多代码会写成如下:
下面的代码是无效的哈. timer 造成了内存泄漏,是不可能调用析构方法的
deinit {
print("销毁了")
timer?.invalidate()
timer = nil
}
还有会在viewWillDisappear 写. 但是这种 如果是 push 到下一个界面也会调用, 也是不太符合需求的
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
timer?.invalidate()
timer = nil
}
正确的方法
第一种方案
override func didMove(toParent parent: UIViewController?) {
if parent == nil {
timer?.invalidate()
timer = nil
}
}
结果: 销毁成功
第二种方案
造成循环引用的根本原因是 timer 强引用了 self. 我们需要打破这个循环引用. 加入一个 target 利用消息转发来完善
var index: Int = 0
var timer: Timer?
var target = NSObject()
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .white
// Do any additional setup after loading the view.
class_addMethod(NSObject.self, #selector(log), class_getMethodImplementation(Self.self, #selector(IMPLog))!, "V@:@")
timer = Timer.scheduledTimer(timeInterval: 1, target: target, selector: #selector(log), userInfo: nil, repeats: true)
}
@objc func IMPLog() {
print("imp 转发")
}
deinit {
print("销毁了")
timer?.invalidate()
timer = nil
}
结果: 销毁成功
网友评论