代码基于swift 4.0。
一、在不需要的时候invalidate()。
当控制器和timer循环引用时,不能将 timer?.invalidate() 放在 deinit 方法中,因为控制器不会被释放掉,deinit方法不会被调用。
不需要定时器的时候invalidate,例如可以在viewDidDisappear 中释放掉。因为Timer会对target强引用,只有当timer被invalidate才会取消强引用。官方描述:
target
The object to which to send the message specified by aSelector when the timer fires. The timer maintains a strong reference to target until it (the timer) is invalidated.
override func viewDidDisappear(_ animated: Bool) {
timer?.invalidate()
timer = nil
}
override func viewDidLoad() {
super.viewDidLoad()
configureUI()
timer = Timer.scheduledTimer(timeInterval: 2, target: self, selector: #selector(handerTimer), userInfo: nil, repeats: true)
}
@objc func handerTimer() {
print("timer")
}
注:尝试传weakSelf Timer.scheduledTimer 的target对象,还是会发生引用循环。因为Timer 对target强引用,强引用一个weak 变量,对变量所指的对象仍然是强引用。
//此种方式无效。
weak var weakSelf = self
timer = Timer.scheduledTimer(timeInterval: 2, target: weakSelf!, selector: #selector(handerTimer), userInfo: nil, repeats: true)
二、在timer初始化的block中弱引用控制器。(这种方式仅限于@available(iOS 10.0, *))
timer弱引用控制器,那么就不会造成循环引用,控制器可以正常的释放掉。deinit方法会调用。
var timer: Timer?
deinit {
timer?.invalidate()
timer = nil
}
override func viewDidLoad() {
super.viewDidLoad()
// 下面方法@available(iOS 10.0, *)
timer = Timer.scheduledTimer(withTimeInterval: 2, repeats: true, block: { [weak self] (_) in
self?.handerTimer()
})
}
三、第二种方式只能在iOS10.0上使用。为了兼容以下版本,封装一个block类方法,通过userInfo传递。
self -> timer timer --->self timer弱引用self 不存在循环引用
Timer 循环引用自己
override func viewDidLoad() {
super.viewDidLoad()
// [weak self] 不能忘
timer = Timer.xx_scheduledTimer(withTimeInterval: 2, repeats: true, block: { [weak self] (_) in
self?.handerTimer()
})
}
@objc func handerTimer() {
print("timer")
}
// 写一个Timer的分类。
extension Timer {
//兼容不同版本
class func xx_scheduledTimer(withTimeInterval interval: TimeInterval, repeats: Bool, block: @escaping (Timer) -> Void) -> Timer {
if #available(iOS 10.0, *) {
return Timer.scheduledTimer(withTimeInterval: interval, repeats: repeats, block: block)
}
return scheduledTimer(timeInterval: interval, target: self, selector: #selector(xx_handerTimerAction(_:)), userInfo: Block(block), repeats: true)
}
// 一定要加class。 Timer是类对象,只能调用类方法,不能调用实例方法(否则报错:[NSTimer xx_handerTimerAction:]: unrecognized selector sent to class 0x1105c30c0')
@objc class func xx_handerTimerAction(_ sender: Timer) {
if let block = sender.userInfo as? Block<(Timer) -> Void> {
block.type(sender)
}
}
}
//Block模型类
class Block<T> {
let type: T
init(_ type: T) {
self.type = type
}
}