Swift 4 中带有 Date() 的倒数和倒数计时器应该在一段时间后停止



我对 Swift 很陌生,并且已经通过这里的问题学到了很多东西。

在我的第一个项目中,我尝试编写一个足球游戏时间计时器应用程序。按下哨子按钮后,第一个计时器正在计数,显示播放的分钟数,第二个计时器倒计时到零,显示剩余的分钟数。到目前为止,这有效。

现在两个计时器都应该在中场休息结束时自动停止,这样我就可以开始第三个加时计时器了。到目前为止,计时器的 invalidate 语句不起作用 - 两个计时器都继续运行。我的 if 语句似乎有问题,但目前我不知道是什么。因此,任何帮助将不胜感激。

var countUpClock: Timer?
var countDownClock: Timer?
private var formatter: DateComponentsFormatter = {
    let formatter = DateComponentsFormatter()
    formatter.unitsStyle = .positional
    formatter.allowedUnits = [.minute, .second]
    formatter.zeroFormattingBehavior = .pad
    return formatter
}()
func runPlaytimeClocks() {
    let startTime = Date()
    let countTime = Date() + 2700 //45min of playtime
    if startTime <= countTime {
        countUpClock = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
        self?.timePlayed.text = self?.formatter.string(from: startTime, to: Date())
        }
    }
    else {
        countUpClock?.invalidate()
        }

    if startTime <= countTime {
        countDownClock = Timer.scheduledTimer(withTimeInterval: -1.0, repeats: true) { [weak self] _ in
            self?.timetoPlay.text = self?.formatter.string(from: Date(), to: countTime)
            }
        }
    else {
        countDownClock?.invalidate()
}

非常感谢您的回复。

在这里找到了我想要的东西:http://ioscake.com/swift-nstimer-in-background.html

我根据我的时钟调整了解决方案(CountUpClock,CountDownClock,OvertimeClock,HalftimeClock)。

你有什么建议吗,开始足球比赛下半场的最佳解决方案是什么?

到目前为止,当我在中场休息后按下哨声按钮时,CountUpClock 在 0:00 再次开始。但它应该从 45:00 分钟到 90:00 继续运行 - 而 CountDownClock 应该再次从 45:00 倒计时到 0:00。

对于这种行为,最好的解决方案是什么?

import UIKit
import UserNotifications
private let stopTimeKey = "stopTimeKey"
class ViewController: UIViewController {
//Outlets
@IBOutlet weak var timePlayed: UILabel!
@IBOutlet weak var timeToPlay: UILabel!
@IBOutlet weak var overtime: UILabel!
@IBOutlet weak var halftime: UILabel!
@IBOutlet weak var halftimeButton: UIButton!
private var stopTime: Date?
override func viewDidLoad() {
    super.viewDidLoad()
    registerForLocalNotifications()
    stopTime = UserDefaults.standard.object(forKey: stopTimeKey) as? Date
    if let time = stopTime {
        if time > Date() {
            startTimers(time, includeNotification: false)
        } else {
            notifyTimerCompleted()
        }
    }
}
private func registerForLocalNotifications() {
    if #available(iOS 10, *) {
           UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound]) { granted, error in
            guard granted && error == nil else {
                // display error
                print("(String(describing: error))")
                return
            }
        }
    } else {
        let types: UIUserNotificationType = [.badge, .sound, .alert]
        let settings = UIUserNotificationSettings(types: types, categories: nil)
        UIApplication.shared.registerUserNotificationSettings(settings)
    }
}
//Actions
@IBAction func whistleButtonTapped(_ sender: UIButton) {
    overtimeClock?.invalidate()
    overtimeClock = nil
    halftimeClock?.invalidate()
    halftimeClock = nil
    overtime.text = "00:00"
    halftime.text = "00:00"
    halftimeButton.isHidden = true
        //add 10 seconds per halftime to try out
        let time = Date() + 10
        if time > Date() {
            startTimers(time)
        } else {
            timeToPlay.text = "error"
        }
    }
@IBAction func halftimeButton(_ sender: UIButton) {
    halftimeButtoPressed()
}
// Code for different Timers
private var countDownClock: Timer?
private var countUpClock: Timer?
var overtimeClock: Timer?
var halftimeClock: Timer?
private func startTimers(_ stopTime: Date, includeNotification: Bool = true) {
    // save `stopTime` in case app is terminated
    UserDefaults.standard.set(stopTime, forKey: stopTimeKey)
    self.stopTime = stopTime
    // start Timer
    countDownClock = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(handleCountDownTimer(_:)), userInfo: nil, repeats: true)
    countUpClock = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(handleCountUpTimer(_:)), userInfo: nil, repeats: true)
    guard includeNotification else { return }
    // start local notification (so we're notified if timer expires while app is not running)
    if #available(iOS 10, *) {
        let content = UNMutableNotificationContent()
        content.title = "Overtime is starting soon"
        content.body = "In 5 seconds the overtime will start"
        content.sound = UNNotificationSound.default()
        //5 seconds warning before overtime starts
        let trigger = UNTimeIntervalNotificationTrigger(timeInterval: stopTime.timeIntervalSinceNow - 5, repeats: false)
        let notification = UNNotificationRequest(identifier: "timer", content: content, trigger: trigger)
        UNUserNotificationCenter.current().add(notification)
    } else {
        let notification = UILocalNotification()
        //5 seconds warning before overtime starts
        notification.fireDate = stopTime - 5 
        notification.alertBody = "Overtime is starting soon"
        UIApplication.shared.scheduleLocalNotification(notification)
    }
}
private func stopTimer() {
    countDownClock?.invalidate()
    countDownClock = nil
    countUpClock?.invalidate()
    countUpClock = nil
}
private func halftimeButtoPressed() {
    overtimeClock?.invalidate()
    overtimeClock = nil
    startHalftimeClock()
    halftimeButton.isHidden = true
}
private let dateComponentsFormatter: DateComponentsFormatter = {
    let _formatter = DateComponentsFormatter()
    _formatter.allowedUnits = [.minute, .second]
    _formatter.unitsStyle = .positional
    _formatter.zeroFormattingBehavior = .pad
    return _formatter
}()
@objc func handleCountDownTimer(_ timer: Timer) {
    let now = Date()
    if stopTime! > now {
        timeToPlay.text = dateComponentsFormatter.string(from: now, to: stopTime!)
    } else {
        stopTimer()
        notifyTimerCompleted()
        startOvertimeClock()
        halftimeButton.isHidden = false
    }
}
@objc func handleCountUpTimer(_ timer: Timer) {
    //add 10 seconds per halftime to try out
    let now = Date() + 10
    if now > stopTime! {
        timePlayed.text = dateComponentsFormatter.string(from: stopTime!, to: now)
    } else {
        stopTimer()
        notifyTimerCompleted()
    }
}
//Overtime Clock
@objc func startOvertimeClock() {
    let startOvertime = Date()
    overtimeClock = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { [weak self] _ in
        self?.overtime.text = self?.dateComponentsFormatter.string(from: startOvertime, to: Date())
    }
}
//Halftime Clock
@objc func startHalftimeClock() {
    let startHalftime = Date()
    halftimeClock = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { [weak self] _ in
        self?.halftime.text = self?.dateComponentsFormatter.string(from: startHalftime, to: Date())
    }
}
private func notifyTimerCompleted() {
    timeToPlay.text = "End"
    timePlayed.text = "End"
}
}

最新更新