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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

1回答

825閲覧

配列要素に対して処理を行い、その処理後に次のインデックスに対応する要素も同じ処理をする方法

at3250

総合スコア8

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2020/05/25 10:18

編集2020/05/25 12:57

前提・実現したいこと

現在、swiftにてカウントダウンタイマーを作成しています。実現したい事としてはユーザーがインターバルを複数セットし、セットしたインターバルが過ぎた時点で通知をし、次のインターバルに移り、トータルの残り時間が0秒になったらタイマーを終了する機能を作成中です。

例)セットされたインターバル:20秒→1分→30秒
流れ:ユーザーがタイマーをスタート→20秒のタイマーがスタート→20秒タイマーが0秒でになったタイミングで音が鳴り、それと同時に1分タイマーがスタート→1分タイマーが0秒でになったタイミングで音が鳴り、それと同時に30秒タイマーがスタート→30秒タイマーが0秒になったら音が鳴り終了

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

現在はそれぞれのインターバルを配列に格納し、上記のことを実装できないかと考えています。そのためには配列内の最初の要素(20)に対してTimerをスタートさせ、その要素が0になった時に次のインデックスに移り、それに対応している要素(60)のカウントダウンをスタートさせるようにしたいのですが、そのやり方がリサーチをしても見つかりません。配列での実装に固執しているわけではありませんので、配列に格納しなくとも上記のことが実装することが可能であれば、その方法もご教示いただけると幸いです。

コード

下記のコードではセットされた合計時間のカウントダウンの実装+セットされた各インターバルをラベルに表示のみ。そして、終了3秒前からカウントダウンの音源を流すようにしている。

import UIKit import AVFoundation import Foundation class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource{ @IBOutlet weak var pickerOutlet: UIPickerView! @IBOutlet weak var intervalOutlet: UILabel! @IBOutlet weak var currentIntervalOutlet: UILabel! @IBOutlet weak var timeOutlet: UILabel! var count = 0 var audioPlayer = AVAudioPlayer() var timer = Timer() var intervalTimer = Timer() let dataList = [[Int](0...24), [Int](0...60), [Int](0...60)] var hourList: [Int] = [] var minList: [Int] = [] var secList: [Int] = [] var intervalList: [String] = [] var currentIntervalList: [Int] = [] var totalTime = 0 var isPause = false var isStarted = false override func viewDidLoad() { super.viewDidLoad() pickerOutlet.delegate = self pickerOutlet.dataSource = self do { let audioPath = Bundle.main.path(forResource: "sound", ofType: ".mp3") try audioPlayer = AVAudioPlayer(contentsOf: URL(fileURLWithPath: audioPath!)) } catch { } } func numberOfComponents(in pickerView: UIPickerView) -> Int { return dataList.count } func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { return dataList[component].count } func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { return String(dataList[component][row]) } func pickerView(_ pickerView: UIPickerView, widthForComponent component:Int) -> CGFloat { return pickerOutlet.bounds.width * 1/4 } @IBOutlet weak var setOutlet: UIButton! @IBAction func set(_ sender: UIButton) { let selectedRow1 = self.pickerOutlet.selectedRow(inComponent: 0) let selectedRow2 = self.pickerOutlet.selectedRow(inComponent: 1) let selectedRow3 = self.pickerOutlet.selectedRow(inComponent: 2) let hours = dataList[0][selectedRow1] let mins = dataList[1][selectedRow2] let secs = dataList[2][selectedRow3] let total = hours * 3600 + mins * 60 + secs currentIntervalList.append(total) if (hours != 0 && mins != 0 && secs != 0) { let interval = String(hours) + "h" + String(mins) + "m" + String(secs) + "s" intervalList.append(interval) } else if (hours != 0 && mins != 0 && secs == 0) { let interval = String(hours) + "h" + String(mins) + "m" intervalList.append(interval) } else if (hours != 0 && mins == 0 && secs == 0) { let interval = String(hours) + "h" intervalList.append(interval) } else if (hours == 0 && mins != 0 && secs != 0) { let interval = String(mins) + "m" + String(secs) + "s" intervalList.append(interval) } else if (hours == 0 && mins != 0 && secs == 0) { let interval = String(mins) + "m" intervalList.append(interval) } else if (hours == 0 && mins == 0 && secs != 0) { let interval = String(secs) + "s" intervalList.append(interval) } hourList.append(hours) minList.append(mins) secList.append(secs) var totalHours = 0; for hour in hourList { totalHours += hour } var totalMins = 0; for min in minList { totalMins += min } var totalSecs = 0; for sec in secList { totalSecs += sec } let hoursDisplayed = String(format: "%02d", totalHours) let minsDisplayed = String(format: "%02d", totalMins) let secsDisplayed = String(format: "%02d", totalSecs) intervalOutlet.text = intervalList.joined(separator: ",") timeOutlet.text = "(hoursDisplayed) : (minsDisplayed) : (secsDisplayed)" startOutlet.isEnabled = true backOutlet.isEnabled = true } @IBOutlet weak var startOutlet: UIButton! @IBAction func start(_ sender: UIButton) { if (!isStarted) { var hour = 0; for h in hourList { hour += h } var min = 0; for m in minList { min += m } var sec = 0; for s in secList { sec += s } count = hour * 3600 + min * 60 + sec isStarted = true if !isPause { timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(ViewController.counter), userInfo: false, repeats: true) startOutlet.setTitle("Pause", for: UIControl.State.normal) isPause = true } else if isPause { timer.invalidate() isPause = false startOutlet.setTitle("Start", for: UIControl.State.normal) } } else { if !isPause { timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(ViewController.counter), userInfo: false, repeats: true) startOutlet.setTitle("Pause", for: UIControl.State.normal) isPause = true } else if isPause { timer.invalidate() isPause = false startOutlet.setTitle("Start", for: UIControl.State.normal) } } setOutlet.isHidden = true backOutlet.isHidden = true pickerOutlet.isHidden = true } @objc func counter(){ count -= 1 var countCopy = count var hour = 0 var min = 0 var sec = 0 hour = countCopy / 3600 countCopy %= 3600 min = countCopy / 60 countCopy %= 60 sec = countCopy let Hour = String(format: "%02d", hour) let Min = String(format: "%02d", min) let Sec = String(format: "%02d", sec) timeOutlet.text = "(Hour) : (Min) : (Sec)" if (count == 3) { audioPlayer.play() } if (count == 0) { timer.invalidate() startOutlet.isEnabled = false } } }

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

Swift: 4.2
Xcode: 10.1

現在のUI

イメージ説明

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2020/05/25 10:48

作成されたタイマーのコードはどんなものでしょうか?
退会済みユーザー

退会済みユーザー

2020/05/25 11:10 編集

コードは質問文に追記してmarkdown形式で整形してくれませんか?見るのが辛いです。
miyabi_takatsuk

2020/05/25 12:42

tyobigorouさんのコメント通り、 そのコードを、質問本文に、コードブロックを使って、記載してください。
at3250

2020/05/25 12:58

ご指摘ありがとうございます。修正いたしました。
guest

回答1

0

ベストアンサー

ベタ書きはあとあとつらくなるので、自分ならこんな感じで作っていくと思います。

swift

1class IntervalTimer { 2 3 var timeInterval: TimeInterval! 4 5 init(timeIntarval: TimeInterval) { 6 self.timeInterval = timeIntarval 7 } 8 9 func start() { 10 // timerを動かしてdelegateでVCに処理を移譲する。 11 } 12 13 func stop() { 14 } 15 16 func pouse() { 17 } 18 19 func finished() { 20 } 21 22} 23 24class IntervalTimers { 25 26 var intervalTimers = [IntervalTimer]() 27 28 var currentIntervalTimerIndex = 0 29 30 func startTimer() { 31 if intervalTimers.isEmpty { return } 32 currentIntervalTimerIndex = 0 33 intervalTimers[currentIntervalTimerIndex].start() 34 } 35 36 func endIntervalTimer() { 37 if currentIntervalTimerIndex >= intervalTimers.count - 1 { return } 38 currentIntervalTimerIndex += 1 39 intervalTimers[currentIntervalTimerIndex].start() 40 } 41 42 func setTimer(timeInterval: TimeInterval) { 43 intervalTimers.append(IntervalTimer(timeIntarval: timeInterval)) 44 } 45} 46 47class ViewController: UIViewController { 48 49 var intervalTimer = IntervalTimers() 50 51 // タイマーをどこに置くのが適当かわからないのでとりあえずここに置く。 52 // 置き場所によって処理が変わってくるが 53   var timer = Timer() 54 55 56 // スタートボタンがタップされた場合の処理 57 @IBAction func startBtnDidTap(_ sender: UIButton) { 58 intervalTimer.startTimer() 59 } 60 61 // intervalTimerが終了を検知した場合の処理->次のintervalTimerを動かす 62 func hoge() { 63 intervalTimer.endIntervalTimer() 64 } 65} 66 67

ベタ書きのままの場合は、
実行しているインターバルのインデックスを覚えておいて、

swift

1if (count == 0) { 2timer.invalidate() 3startOutlet.isEnabled = false 4

の箇所でtimerに配列の次の値(覚えたおいたインターバルのインデックスの次)を与えて再スタートさせればいいんじゃないでしょうか?

投稿2020/05/25 14:36

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

at3250

2020/05/26 08:45

ご丁寧なご説明ありがとうございます。頂いた回答を参考にこれから取り組みたいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問