我对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()
}
答案 0 :(得分:0)
非常感谢您的回复。
我在这里找到了我想要的内容: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"
}
}