我正在开发第二个应用程序,学习Swift。我的第一个是一个计算器,当按下按钮时,该计算器根据许多UITextField输入输出一些结果。
我现在已经完成了一个倒计时计时器,通过在线教程进行操作。
如何使用UITextField中输入的数字设置持续时间(“秒”变量)?我尝试使用
var seconds = Double(timeSetupField.text!)!
代替
var seconds = 60
但是我知道这是行不通的,但是我不确定为什么。属性初始化程序在“自我”可用之前运行,但是我没有使用“自我”。 -我怀疑我误会了一些东西。变量的使用比我简单的计算器要复杂一些。
任何有关如何实现此建议的建议都是很好的,对上述问题的任何解释也将受到赞赏。
代码:
//
// ViewController.swift
// CountdownTimer
//
// Created by Matt Baines on 01/09/2018.
// Copyright © 2018 Matt Baines. All rights reserved.
//
import UIKit
class ViewController: UIViewController {
// PROPERTIES
@IBOutlet weak var timeSetupField: UITextField!
@IBOutlet weak var timeCountdownLabel: UILabel!
@IBOutlet weak var enterTimeLabel: UILabel!
@IBOutlet weak var pauseButton: UIButton!
@IBOutlet weak var startButton: UIButton!
// DECLARATION OF VARIABLES
// This variable will hold a starting value of seconds.
var seconds = 60
// Timer variable
var timer = Timer()
//This will be used to make sure only one timer is created at a time.
var isTimerRunning = false
// For pause & resume
var resumeTapped = false
override func viewDidLoad() {
super.viewDidLoad()
// Disable pause button so it is not visible until a time is started.
pauseButton.isEnabled = false
}
func runTimer() {
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector:(#selector(ViewController.updateTimer)), userInfo: nil, repeats: true)
isTimerRunning = true
pauseButton.isEnabled = true
}
@objc func updateTimer() {
if seconds < 1 {
timer.invalidate()
} else {
// This will decrement the seconds.
seconds -= 1
// This will update the label.
timeCountdownLabel.text = timeString(time: TimeInterval(seconds))
}
}
func timeString(time:TimeInterval) -> String {
let hours = Int(time) / 3600
let minutes = Int(time) / 60 % 60
let seconds = Int(time) % 60
return String(format:"%02i:%02i:%02i", hours, minutes, seconds)
}
@IBAction func startButton(_ sender: UIButton) {
if isTimerRunning == false {
runTimer()
self.startButton.isEnabled = false
}
}
@IBAction func pauseButton(_ sender: UIButton) {
if self.resumeTapped == false {
timer.invalidate()
self.resumeTapped = true
self.pauseButton.setTitle("Resume", for: .normal)
} else {
runTimer()
self.resumeTapped = false
self.pauseButton.setTitle("Pause", for: .normal)
}
}
@IBAction func resetButton(_ sender: UIButton) {
timer.invalidate()
// Manually enter the restarting point for the seconds
seconds = 60
timeCountdownLabel.text = timeString(time: TimeInterval(seconds))
isTimerRunning = false
// Ensure pause button text is set back to pause
self.pauseButton.setTitle("Pause", for: .normal)
pauseButton.isEnabled = false
startButton.isEnabled = true
}
}
答案 0 :(得分:0)
您只是要替换代码行
var seconds = 60
与
var seconds = Double(timeSetupField.text!)!
您在哪里声明变量?如果是这种情况,这就是您的问题所在。
“ Self”(表示视图控制器)直到viewDidLoad才加载。在加载视图之前,您无法访问IBOutlets。您正试图从IBOutlet获取“尚不存在”的信息。
如果在情节提要中已经在timeSetupField上设置了一些文本,则可以执行以下操作:
//Global Variables
var seconds = 60
//Life cycle
override func viewDidLoad() {
super.viewDidLoad()
pauseButton.isEnabled = false
// Checks to make sure the timeSetupField.text isn't nil. If it is nil, you will not run any more code within viewDidLoad which prevents a crash on the next line if timeFromTextField is nil.
guard let timeFromTextField = timeSetupField.text else { return }
seconds = timeFromTextField
}
此时,您的视图已加载,并且可以访问timeSetupField.text。您可以使用默认值全局声明秒数,以便可以在ViewController文件中的任何位置访问它,但是在插座可用后在ViewDidLoad中设置该值。
在这种情况下,您可以从代码中的任何函数(例如IBAction或在按下键盘上的Enter时调用的函数)中安全地更改秒变量。
答案 1 :(得分:0)
您已经有了一个很好的开始,但是可以通过分离计时器逻辑和查看控制器代码来改进代码-这将使计时器更易于测试,并允许您在其他地方重用它。下面的代码不完整,但是可以正常工作,它将使您开始分离UI和逻辑。祝您第二个应用程序好运!
class ViewController: UIViewController {
@IBOutlet weak var timeSetupField: UITextField!
@IBOutlet weak var timeCountdownLabel: UILabel!
@IBOutlet weak var pauseButton: UIButton!
@IBOutlet weak var startButton: UIButton!
var seconds = 60
var timer: SecondsTimer?
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
updateTimeLabel(newSeconds: 60)
}
func updateTimeLabel(newSeconds: Int) {
let hours = newSeconds / 3600
let minutes = newSeconds / 60 % 60
let seconds = newSeconds % 60
let timeStr = String(format:"%02i:%02i:%02i", hours, minutes, seconds)
timeCountdownLabel.text = timeStr
timeCountdownLabel.sizeToFit()
}
@IBAction func startButton(_ sender: UIButton) {
timer = SecondsTimer.init(callback: timerUpdate)
timer?.start(initialSeconds: 60)
self.startButton.isEnabled = false
}
private func timerUpdate(seconds: Int) {
if seconds > 0 {
updateTimeLabel(newSeconds: seconds)
} else {
timer?.stop()
}
}
@IBAction func pauseButton(_ sender: UIButton) {
guard let timer = timer else { return }
if timer.paused {
pauseButton.setTitle("Pause", for: .normal)
} else {
pauseButton.setTitle("Resume", for: .normal)
}
pauseButton.sizeToFit()
timer.paused = !timer.paused
}
@IBAction func resetButton(_ sender: UIButton) {
timer?.reset()
updateTimeLabel(newSeconds: 60)
}
}
class SecondsTimer: NSObject {
var paused = false
var stopReqest = false
var seconds = 0
let callback: (Int)->()
init(callback: @escaping (Int)->()) {
self.callback = callback
super.init()
NotificationCenter.default.addObserver(self, selector: #selector(SecondsTimer.applicationDidBecomeActiveNotification), name: NSNotification.Name.UIApplicationDidBecomeActive, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(SecondsTimer.applicationWillResignActiveNotification), name: NSNotification.Name.UIApplicationWillResignActive, object: nil)
}
deinit {
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIApplicationDidBecomeActive, object: nil)
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIApplicationWillResignActive, object: nil)
print("timer deinit")
}
func start(initialSeconds: Int = 60) {
paused = false
stopReqest = false
seconds = initialSeconds
Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(self.deccrementSeconds), userInfo: nil, repeats: true)
}
@objc func reset() {
seconds = 60
}
func stop() {
stopReqest = true
}
@objc func applicationDidBecomeActiveNotification() {
paused = false
}
@objc func applicationWillResignActiveNotification() {
paused = true
}
@objc func deccrementSeconds(timer: Timer) {
if stopReqest {
timer.invalidate()
return
}
if paused == false {
seconds -= 1
callback(seconds)
}
}
}