Подскажите как сделать цикл с задержками выполнения, при этом не блокируя основную работу пользовательского интерфейса?


#1

Всем привет допустим есть массив с задержками по времени
var delays: [Int] = [5, 10, 12, 13 , 4, 7, 9]
подскажите как организовать цикл чтобы в начале каждой итерации выполнять мне нужные действия а остальное время ничего не выполнять, те на первой итерации мы получаем задержку в 5 секунд отослали команды и ждем 5 секунд и ничего не делаем, далее получили задержку в 10 секунд отослали команды и ждем еще 10 секунд и ничего не делаем и так далее по всему массиву задержек. Так же нужна возможность остановить этот цикл. Подскажите как реализовать такое, ничего не приходит на ум, может кто-то подобное уже делал, заранее всем откликнувшимся спасибо.


#2

Все элементарно - таймер.
Создаете метод, который будет запускаться через время по таймеру. В начале метода переопределяете таймер с нужной задержкой. Делаете свои операции. Нужен будет еще параметр, который будет трекать индекс задержки в массиве.
Так же в любой момент можно таймер убить и дальше ничего не пойдет.


#3

Можете посмотреть тут
https://refactoring.guru/ru/design-patterns/command/swift/example#example-1


#4

Это уже по феншую и по взрослому.


#5

РексХант привет, написал по твоему совету можешь глянуть, может где улучшить что-то нужно

let delays: [Double] = [1, 2, 3, 2, 2, 1, 3, 4, 1, 1, 2, 1, -1]
var indexDelays: Int = 0
var timeOfDelay: Double = 0
var isPlayScene: Bool = false

    let timer = Timer.scheduledTimer(withTimeInterval: 0.005, repeats: true) { timer in
        if isPlayScene == false {
            print("play scene \(indexDelays + 1) - \(Date())")
            isPlayScene = true
            timeOfDelay = timeOfDelay + 0.005
        } else {
            if timeOfDelay > delays[indexDelays] {
                isPlayScene = false
                timeOfDelay = 0
                indexDelays = indexDelays + 1
                if indexDelays == delays.count - 1 {
                    if delays[indexDelays] == -1 {
                        indexDelays = 0
                        print("restart play scenes")
                    } else {
                        timer.invalidate()
                        print("stop play scenes")
                    }
                }
            } else {
                timeOfDelay = timeOfDelay + 0.005
            }
        }
    }

в конце массива задержек -1 рестарт, 0 окончание


#6

Я с таймером мало работал, но я бы попробовал без timeOfDelay. Можно же сам таймер каждый раз переопределять и в нем эту вашу задержку и ставить, через сколько времени вызывать тело заного. В итоге код стал бы проще и понятнее.
Но вопрос в другом, целесообразно ли переопределять таймер.


#7

При взаимодействии с UI ваш таймер не будет работать
Для того чтобы он работал, нужно создавать таймер и добавлять его в ранлуп


#8

Да Джек только хотел добавить сюда, при создании таймера нужно добавить таймер в ранлуп,

let timer = Timer.scheduledTimer(withTimeInterval: 0.005, repeats: true) { ... }
RunLoop.current.add(timer, forMode: .common)

вот так, может кому-то это пригодится.