ios - 某些 App Actions 打破了 TImer?

标签 ios swift multithreading timer nsuserdefaults

我有一个在我的应用程序上运行的计时器,当用户离开 View 并返回 View 时,它使用保存和重新加载功能。但是,如果我在我的应用程序上转到不同的选项卡,该选项卡所需的操作似乎会破坏计时器。

这是否是由于应用程序中的线程使用和其他选项卡的核心数据打破了计时器计数?这是我的定时器代码

更新 2:这是我修改后的完整计时器代码......

// MARK: - SETTING UP SETS & TIMERS

    func createStopTimeForRestFromUserTime(userTime: Int) -> Date {
        let calendar = Calendar.current
        let stopDate = calendar.date(byAdding: .second, value: userTime, to: Date())
        return stopDate!
    }

    func createTimer(stopDate: Date) {
        print("CONSTRUCTING A TIMER")
        userDefaults.set(stopDate, forKey: "setStopDate")
        restTimer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(RestController.updateRestTimer), userInfo: nil, repeats: true)
    }

    func updateRestTimer() {
        let presentTime = Date()
        let stoppedTime = UserDefaults.standard.object(forKey: "setStopDate") as? Date

        if stoppedTime?.compare(presentTime) == ComparisonResult.orderedDescending {
                restRemainingCountdownLabel.text = dateComponentsFormatter.string(from: presentTime, to: stoppedTime!) 
            } else {
                self.stopTimer()
                print("THE TIMER IS NOW FINISHED")
            }
        }

    func stopTimer() {
        self.restTimer.invalidate()
    }

    // MARK: - CONFIGURE TIMER ON OPEN / CLOSE

    override func viewWillDisappear(_ animated: Bool) {
        print("VIEWWILLDISAPPEAR WAS CALLED")
        stopTimer()
        NotificationCenter.default.post(name: NSNotification.Name(rawValue: "ViewDidChangeNotification"), object: NSDate())
    }

    func handleResumedTime(disappTime: NSDate) {
        let disappearedTime = disappTime
        let resumeTime = NSDate()

        if disappearedTime.compare(resumeTime as Date) == ComparisonResult.orderedDescending {
            print("RESUMING THE TIMER")
            self.createTimer(stopDate: disappearedTime as Date)
        } else {
            print("TIMER HAS FINISHED")
            stopTimer()
        }
    }

    func handleTimerCallback(notification: NSNotification) {
        if let date = notification.object as? NSDate {
            self.handleResumedTime(disappTime: date)
        }
    }

备用 VC id 开关中的代码导致损坏:

override func viewDidLoad() {
    NotificationCenter.default.addObserver(self, selector:  #selector(RoutineController.handleTimerCallback(notification:)), name: NSNotification.Name(rawValue: "ViewDidChangeNotification"), object: nil)
}

override func viewWillDisappear(_ animated: Bool) {
    NotificationCenter.default.post(name: NSNotification.Name(rawValue: "ViewDidChangeNotification"), object: NSDate())
}

func handleTimerCallback(notification: NSNotification) {
    let date = notification.object
    print("Object is \(date)")
}

编辑:添加了更新的 handleResumed 函数和控制台打印输出,当更改选项卡并再次更改回来时...

    func handleResumedTime(disappTime: NSDate) {
    let disappearedTime = disappTime as Date
    let resumeTime = NSDate() as Date
    print("ATTEMPTING RESUME")
    print(disappearedTime)
    print(resumeTime)

    if resumeTime.compare(disappearedTime) == ComparisonResult.orderedAscending {
        print("RESUMING THE TIMER")
        self.createTimer(stopDate: disappearedTime)
    } else {
        print("TIMER HAS FINISHED")
        stopTimer()
    }
}

enter image description here

最佳答案

尝试使用 DateFormatter 以毫秒为单位比较计时器,并使用 Notifications 在 Controller 之间传递数据。

每次切换标签时都会调用此函数。它使计时器无效,停止滴答,并以毫秒为单位保存时间。

override func viewWillDisappear(_ animated: Bool) {

    restTimer.invalidate()

    let df = DateFormatter()
    df.dateFormat = "y-MM-dd H:m:ss.SSSS"

    let disappearingDate = Date()
    let disappearingDateInMilliseconds = df.string(from: disappearingDate)

    NotificationCenter.default.post(name: NSNotification.Name(rawValue: "kViewDidChangeExampleNotification"), object: disappearingDateInMilliseconds)
}



/* add your Notification observers in each view controller */
override func viewDidLoad() {
    NotificationCenter.default.addObserver(self, selector:  #selector(ViewController.handleTimerCallback(notification:)), name: NSNotification.Name(rawValue: "kViewDidChangeExampleNotification"), object: nil)
}

您需要定义将处理每个 Controller 中的通知的函数:

func handleTimerCallback(notification: NSNotification) {
    if let dateString = notification.object as? String {
        print("Object is an String: \(notification.object)")

        resumeTimerWithDate(dateString)
    } else {
        print("Object is not of type String: \(notification.object)")
    }
}

以毫秒为单位比较 Swift 中的日期的快速示例:

func resumeTimerWithDate(dateString: String) {
    let df = DateFormatter()
    df.dateFormat = "y-MM-dd H:m:ss.SSSS"

    let secondDate = Date()
    let secondDateToStr = df.string(from: secondDate)

    if dateString < secondDateToStr {
        print("RESUMING THE TIMER")
        let resumeDate = df.date(from: dateString)
        self.createTimer(resumeDate)
    } else {
        print("TIMER HAS FINISHED")
    }
}

其他需要考虑的事项:您可能想要添加一些打印语句以进行调试/完整性检查,因为某些函数可能先于其他函数触发。例如,与其在 viewWillDisappear 中发布通知,不如尝试在 viewDidDisappear 中发布通知,或使用 prepare(for segue:)

关于ios - 某些 App Actions 打破了 TImer?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41935776/

相关文章:

ios - Sprite 依次跟随多个 CGPath

swift - 裁剪(至 : CGRect) doesn't crop correctly

ios - iOS上是否已弃用AUGraph?如果是这样,什么时候?

ios - 由于二进制文件中的此错误 NSUserTrackingUsageDescription 键,我无法提交新版本(App Store)

Swift 4 Realm Swift 对象

java - "Exception in thread "AWT-EventQueue-0 "java.lang.NullPointerException"按下按钮

java - AsyncTask 在构造函数中被取消

java - 如何在不同线程中执行接受同一类的可运行实例的两个方法?

java - 使用约束布局针对不同的屏幕尺寸进行设计

objective-c - 如何将 UITableViewController 添加到 XCode4 中 UITabViewController 上的 UINavigationController?