質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.79%

swiftでストップウォッチアプリを作りたい

受付中

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 346

score 0

前提・実現したいこと

アップル純正のストップウォッチアプリを作りたいのです。

発生している問題・エラーメッセージ

開始ボタンを押した後に停止ボタンを押し、その後、開始ボタンを押すと停止させた時間分進んで表示されてしまいます。

該当のソースコード

import UIKit

class ViewController: UIViewController {

@IBOutlet weak var minuteLabel: UILabel!
@IBOutlet weak var secondLabel: UILabel!
@IBOutlet weak var subsecondLabel: UILabel!
@IBOutlet weak var lapButton: UIButton!
@IBOutlet weak var startAndStopButton: UIButton!
@IBOutlet weak var tableView: UITableView!
fileprivate var timer: Timer?
fileprivate var startTime = Date()
private var isWorkingTimer = false
private var isPaused = false

override func viewDidLoad() {
super.viewDidLoad()
subsecondLabel.text = "00"
secondLabel.text = "00"
minuteLabel.text = "00"
startAndStopButton.backgroundColor = .green

}

@IBAction func startAndStopButton(_ sender: Any) {
if !isWorkingTimer && !isPaused {
timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(startButtonAction), userInfo: nil, repeats: true)
startTime = Date()
startAndStopButton.backgroundColor = .red
startAndStopButton.setTitle("停止", for: .normal)
//ラップボタンを使えるようにする
isWorkingTimer = true
}else if isWorkingTimer && !isPaused {
timer?.invalidate()
startAndStopButton.backgroundColor = .green
startAndStopButton.setTitle("開始", for: .normal)
//ラップボタンをリセット表示にする
isPaused = true
}else if isWorkingTimer && isPaused {
timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(startButtonAction), userInfo: nil, repeats: true)
startAndStopButton.backgroundColor = .red
startAndStopButton.setTitle("停止", for: .normal)
//リセットボタンをラップ表示にする
isPaused = false
}
}

@objc func startButtonAction(_ sender: Any) {
let currentTime = Date().timeIntervalSince(startTime)
let subsecond = Int((currentTime - floor(currentTime))*100)
let second = Int(fmod(currentTime, 60))
let minute = Int(fmod((currentTime/60), 60))
subsecondLabel.text = String(format:"%02d", subsecond)
secondLabel.text = String(format:"%02d", second)
minuteLabel.text = String(format:"%02d", minute)
}

}

試したこと

どうすればいいのか見当がつきませんでした。

補足情報(FW/ツールのバージョンなど)

swift,xcode共に最新です。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • TsukubaDepot

    2020/10/08 21:29

    次回ご質問される時には、コード部分を ``` で囲むか、あるいは <code> 機能を使ってコードを掲載していただけますでしょうか。
    回答のように、整形された読みやすい表示になりますので、ぜひご協力お願いします。

    キャンセル

回答 1

0

ストップウォッチを作るだけなら、Date型を使う必要は一切ありません。

逆に、時刻の管理を Date().timeIntervalSince(startTime) を使って行なっているため、中断時間も加味される結果となってしまっています。

Timer で 0.01秒ごとの割り込みを使っているわけですから、率直に割り込みごとに 0.01 秒増やして計算させた方が考えるのが楽かと思います。

あるいは、再開させた時にあらためて

    startTime = Date()

させる方法もあります。

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var minuteLabel: UILabel!
    @IBOutlet weak var secondLabel: UILabel!
    @IBOutlet weak var subsecondLabel: UILabel!
    @IBOutlet weak var startAndStopButton: UIButton!
    fileprivate var timer: Timer?
    // MARK: - 開始ボタンを押されてからの時間を Double で記録する
    fileprivate var startTime = 0.0

    private var isWorkingTimer = false
    private var isPaused = false

    override func viewDidLoad() {
        super.viewDidLoad()
        subsecondLabel.text = "00"
        secondLabel.text = "00"
        minuteLabel.text = "00"
        startAndStopButton.backgroundColor = .green

    }

    @IBAction func startAndStopButton(_ sender: Any) {
        if !isWorkingTimer && !isPaused {
            timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(startButtonAction), userInfo: nil, repeats: true)
            // MARK: - 「開始」ボタンが押された瞬間を基準とする
            startTime = 0.0
            startAndStopButton.backgroundColor = .red
            startAndStopButton.setTitle("停止", for: .normal)
            //ラップボタンを使えるようにする
            isWorkingTimer = true
        }else if isWorkingTimer && !isPaused {
            timer?.invalidate()
            startAndStopButton.backgroundColor = .green
            startAndStopButton.setTitle("開始", for: .normal)
            //ラップボタンをリセット表示にする
            isPaused = true
        }
        // TODO: ラップボタンは今は忘れる
    }

    // MARK: - 「開始」ボタンを押された時の時間を起点として計算させるだけ
    @objc func startButtonAction(_ sender: Any) {
        // 0.01秒増やす(TImer の timeInterval と同じ値にする
        startTime += 0.01

        // 100倍した値を100で割ったあまり
        let subsecond = Int(startTime * 100) % 100
        // 60の剰余
        let second = Int(startTime) % 60
        // startTime を 60 で割った値を 60 で割ったあまり
        let minute = Int(startTime / 60) % 60

        subsecondLabel.text = String(format:"%02d", subsecond)
        secondLabel.text = String(format:"%02d", second)
        minuteLabel.text = String(format:"%02d", minute)
    }   
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.79%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る