- iOS中定时器NSTimer和CADisplayLink由于强引用造成互相引用最后无法释放内存情况,如下Controlller
// 控制器强引用link和timer
var link:CADisplayLink?
var timer:Timer?
self.link = CADisplayLink(target: self, selector: #selector(linkAction))
self.link?.add(to: RunLoop.main, forMode: .default)
self.timer = Timer(timeInterval: 1.0, target: self, selector: #selector(timerAction), userInfo: nil, repeats: true)
guard let timer = self.timer else { return }
RunLoop.main.add(timer, forMode: .default)
@objc func linkAction() {
debugPrint(#function)
}
@objc func timerAction() {
debugPrint(#function)
}
deinit {
debugPrint("SecondController 释放")
self.timer?.invalidate()
self.timer = nil
self.link?.invalidate()
self.link = nil
}
当进入控制器后定时任务开启,在退出控制器并没有执行deinit方法,定时任务仍然在执行,此时就是因为定时器和控制器互相引用,造成循环引用,无法释放
- Timer 中有一个block方法可以使用weak的方式解决
self.timer = Timer(timeInterval: 1.0, repeats: true, block: { [weak self](timer) in
self?.timerAction()
})
- 如果没有block方法上述方式就没用,可以使用NSProxy类(代理类)实现,但是swift不能使用NSProxy,可以仿造如下
class WeakProxy: NSObject {
weak var target:NSObjectProtocol?
var selector:Selector?
public init(target: NSObjectProtocol? = nil, selector: Selector? = nil) {
super.init()
self.target = target
self.selector = selector
guard target?.responds(to: selector) == true else { return }
guard let method = class_getInstanceMethod(self.classForCoder, #selector(WeakProxy.redirectionMethod)),
let sel = self.selector else { return }
class_replaceMethod(self.classForCoder, sel, method_getImplementation(method), method_getTypeEncoding(method))
}
@objc func redirectionMethod() {
if self.target != nil {
self.target?.perform(self.selector)
}
}
}
self.link = CADisplayLink(target: WeakProxy(target: self,selector: #selector(linkAction)), selector: #selector(linkAction))
self.link?.add(to: RunLoop.main, forMode: .default)