swift во время выполнения цикла for проходит только первая итерация
Такая задача - делаю табата таймер. Задача - есть периоды работы и отдыха, которые имеют разные длительности. Во вью контролере это все решается с помощью label, но проблемы начинаются тогда с помощью цикла for перебираем тренировки. А именно - он запускает первое упражнение, все правильно отражается, но пока проходит анимация, он успевает проскочить все остальные итерации. Я понимаю, что вопрос решается скорее всего с помощью работы с потоками, но вот как именно - я так не понял, потому что новичек в этом
класс упражнений и тренировки
class Exercise{
var nameOfExercise:String = ""
var isWork:Bool
init(flag:Bool){
isWork = flag
}
init(name:String,flag:Bool){
nameOfExercise = name
isWork = flag
}
}
class Training{
var nameOfTraining:String
var exerciseList:[Exercise] = []
var timeOfWork:Int = 30
var timeOfRest:Int = 15
init(name:String) {
nameOfTraining = name
}
func addExercise(newExercise:Exercise) {
exerciseList.append(newExercise)
}
}
и собственно сам view controller
import UIKit
class ViewController: UIViewController {
var run = 5
var timer:Timer!
var timerIsRun = false
var ex1 = Exercise(name: "run", flag: true)
var ex2 = Exercise(flag: false)
var ex3 = Exercise(name: "push", flag: true)
var training = Training(name: "first")
@IBOutlet var label:UILabel!
override func viewDidLoad() {
super.viewDidLoad()
label.text = "0"
training.addExercise(newExercise: ex1)
training.addExercise(newExercise: ex2)
training.addExercise(newExercise: ex3)
// Do any additional setup after loading the view.
}
func createTimer(){
timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: {_ in
self.changeTimer()})
timerIsRun = true
RunLoop.main.add(timer, forMode: .common)
}
func changeTimer(){
label.text = String(run)
self.run -= 1
if self.run < 0{
label.text = "0"
stopTimer()
timer = nil
}
}
@IBAction func goTraining(){
for exercise in training.exerciseList {
if exercise.isWork == true{
run = training.timeOfWork
createTimer()
} else{
run = training.timeOfRest
createTimer()
}
}
}
}
Ответы (1 шт):
Я переработал ваш код, и вот пример простого таймера с интервалами, можно обойтись одним таймером, просто запускаем отсчет в упражнениях один за другим
class Exercise: Equatable {
var name = ""
var duration = 3
init(name: String, duration: Int) {
self.name = name
self.duration = duration
}
static func == (lhs: Exercise, rhs: Exercise) -> Bool {
lhs.name == rhs.name && lhs.duration == rhs.duration
}
}
enum ExerciseType {
case work
case rest
}
class Training {
var name = ""
var exercises = [Exercise]()
var timeOfWork = 5
var timeOfRest = 3
var currentExcercise: Exercise?
var nextExcersize: Exercise? {
guard
let currentIndex = (exercises.firstIndex { $0 == currentExcercise }),
currentIndex < exercises.count - 1 else {
return nil
}
return exercises[currentIndex + 1]
}
init(name: String) {
self.name = name
}
func addExercise(type: ExerciseType) {
let excercise = Exercise(name: "no name", duration: type == .work ? timeOfWork : timeOfRest)
exercises.append(excercise)
}
func addExercise(name: String, type: ExerciseType) {
let excercise = Exercise(name: name, duration: type == .work ? timeOfWork : timeOfRest)
exercises.append(excercise)
}
}
class ViewController: UIViewController {
var timer:Timer!
var timerIsRun = false
let training = Training(name: "first")
@IBOutlet var label:UILabel!
override func viewDidLoad() {
super.viewDidLoad()
training.addExercise(name: "run", type: .work)
training.addExercise(type: .rest)
training.addExercise(name: "push", type: .work)
training.currentExcercise = training.exercises.first
label.text = String(training.currentExcercise!.duration)
}
func startTimer() {
timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) {_ in
self.updateTimer()
}
}
func stopTimer() {
timer.invalidate()
}
func updateTimer() {
guard let excercise = training.currentExcercise else {
// последнее упражнение сделано
print("done")
stopTimer()
return
}
excercise.duration -= 1
label.text = String(excercise.duration)
print(excercise.name, excercise.duration)
if excercise.duration == 0 {
training.currentExcercise = training.nextExcersize
}
}
@IBAction func goTraining(){
startTimer()
}
}
Вывод получается такой
run 4
run 3
run 2
run 1
run 0
no name 2
no name 1
no name 0
push 4
push 3
push 2
push 1
push 0
done