GCD定时器DispatchSourceTimer崩溃问题

//
//  SecondaryViewController.swift
//  0401
//
//  Created by kqc on 2025/7/30.
//
/*
 * 使用DispatchSourceTimer注意点
 * 1: suspend状态不能调用cancel方法会崩溃
 * 2: 重复调用resume或者suspend方法崩溃,必须成对出现
 * 3: 销毁时如果 resume() -> cancel() -> time = nil 会在特定机型崩溃偶发频率很高 如iPhone13,iPhone16等
 * 针对3的修改,在setCancelHandler中执行对应的销毁操作
 */
import UIKit

class SecondaryViewController: UIViewController {

    var timer: DispatchSourceTimer?
    
    var count = 0
    
    override func viewDidLoad() {
        super.viewDidLoad()
        title = "测试DispatchTime"
        view.backgroundColor = .white
        addNoti()
        createTimer()
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        timer?.suspend()
    }
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        timer?.resume()
    }
    
    func createTimer() {
        timer = DispatchSource.makeTimerSource()
        timer?.schedule(deadline: .now(), repeating: .seconds(2), leeway: .milliseconds(100))
        timer?.setEventHandler(handler: DispatchWorkItem(block: {
            print("测试数据...")
        }))
//        To safely close a file descriptor or destroy a Mach port, a cancellation handler is required for that descriptor or port.
        timer?.setCancelHandler(handler: DispatchWorkItem(block: {[weak self] in
            self?.timer = nil
        }))
    }
    
    func stopTimer() {
        guard let timer = timer else {
            return
        }
        timer.suspend()
    }
    
    func recoverTimer() {
        guard let timer = timer else {
            return
        }
        timer.resume()
    }

    func closeTimer() {
        timer?.resume()
        timer?.cancel()
//        self.timer = nil
    }
    
    
    func delayAction() {
        DispatchQueue.main.asyncAfter(deadline: .now() + 1){
            self.count += 1
            print(self.count)
        }
    }
    
    
    deinit {
        closeTimer()
        removeNoti()
        debugPrint("销毁")
    }
}

extension SecondaryViewController {
    func addNoti() {
        NotificationCenter.default.addObserver(self, selector: #selector(becomeActiveStatu), name: UIApplication.willEnterForegroundNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(resignActiveStatu), name: UIApplication.willResignActiveNotification, object: nil)
    }
    
    func removeNoti() {
        NotificationCenter.default.removeObserver(self)
    }
    
    @objc func becomeActiveStatu() {
        recoverTimer()
    }
    
    @objc func resignActiveStatu() {
        stopTimer()
    }
    
    

}

 

posted @ 2025-07-31 16:04  jisa  阅读(14)  评论(0)    收藏  举报