美文网首页
iOS 高级开发(5)之 NSTimer 解决其内存泄漏问题

iOS 高级开发(5)之 NSTimer 解决其内存泄漏问题

作者: iOS刘耀宗 | 来源:发表于2021-08-30 13:57 被阅读0次

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
    }

结果: 销毁成功

相关文章

网友评论

      本文标题:iOS 高级开发(5)之 NSTimer 解决其内存泄漏问题

      本文链接:https://www.haomeiwen.com/subject/svlbiltx.html