Вы должны использовать повторяющийся таймер, который можно отменить, если вид исчезает.
Например, чтобы вращаться через строки:
import Combine
struct ContentView: View {
@State var message = "Hello, world!"
@State var timer: AnyCancellable?
var body: some View {
VStack {
Text(message)
Button(action: {
self.startRepeatingRotation(with: ["foo", "bar", "baz"])
}) {
Text("Start rotating messages")
}
}.onDisappear {
self.timer?.cancel()
}
}
private func startRepeatingRotation(with messages: [String]) {
guard !messages.isEmpty else { return }
var index = 0
self.message = messages[0]
self.timer = Timer.publish(every: 5, on: .main, in: .common).autoconnect().sink { output in
index = (index + 1) % messages.count
self.message = messages[index]
}
}
}
Или, если вы хотите, чтобы он остановился, когда он добрался до конца последовательности, то есть неповторяющейся последовательности, возможно:
private func startRotation(with messages: [String]) {
guard !messages.isEmpty else { return }
var index = 0
self.message = messages[0]
self.timer = Timer.publish(every: 5, on: .main, in: .common).autoconnect().sink { output in
index += 1
guard index < messages.count else {
self.timer?.cancel()
return
}
self.message = messages[index]
}
}
FWIW,
Никогда не «спать». Вы никогда не хотите блокировать основной поток.
Вы также не должны использовать asyncAfter
. Если вы это сделаете, эти запланированные отправки останутся там, ожидая запуска, даже если вы отклоните рассматриваемое представление. И если временные интервалы слишком далеки в будущем, вы начнете видеть «объединение» этих отдельных вызовов asyncAfter
, а не выполнение их каждые пять секунд, как вы хотели.