Сделайте шаг назад и подумайте о проблеме. Обновление пользовательского интерфейса на регулярной основе на самом деле довольно просто, но оно также ненадежно (оно гарантирует только «по крайней мере» точность), поэтому вы не можете полагаться на него для точного обновления счетчиков или значений на основе времени (т. Е. Вы не должны используйте его для увеличения «второго» значения на каждом тике).
То, что вы хотите - это «якорное» время, из которого вы можете рассчитать общее количество времени работы, а затем рассчитать оставшееся время.
Swift / Apple предоставляет ряд аккуратных API, которые вы можете использовать для выполнения всех этих задач.
Это то, что я бросил вместе на детской площадке ...
import UIKit
// Anchor time
let startTime: Date = Date()
// The total amount of time to wait
let duration: TimeInterval = 200 * 60 // 200 minutes
let formatter = DateComponentsFormatter()
formatter.allowedUnits = [.hour, .minute, .second]
formatter.zeroFormattingBehavior = .dropLeading
formatter.unitsStyle = .short
// The amount of time which has past since we started
var runningTime: TimeInterval = 0
// This is just so I can atrificially update the time
var time: Date = Date()
let cal: Calendar = Calendar.current
repeat {
// Simulate the passing of time, by the minute
// If this was been called from a timer, then you'd
// simply use the current time
time = cal.date(byAdding: .minute, value: 1, to: time)!
// How long have we been running for?
runningTime = time.timeIntervalSince(startTime)
// Have we run out of time?
if runningTime < duration {
// Print the amount of time remaining
print(formatter.string(from: duration - runningTime)!)
}
} while runningTime < duration
Это распечатает ...
3 hr, 18 min, 59 sec
3 hr, 17 min, 59 sec
3 hr, 16 min, 59 sec
3 hr, 15 min, 59 sec
3 hr, 14 min, 59 sec
3 hr, 13 min, 59 sec
3 hr, 12 min, 59 sec
3 hr, 11 min, 59 sec
3 hr, 10 min, 59 sec
3 hr, 9 min, 59 sec
3 hr, 8 min, 59 sec
3 hr, 7 min, 59 sec
3 hr, 6 min, 59 sec
3 hr, 5 min, 59 sec
3 hr, 4 min, 59 sec
3 hr, 3 min, 59 sec
3 hr, 2 min, 59 sec
3 hr, 1 min, 59 sec
3 hr, 0 min, 59 sec
2 hr, 59 min, 59 sec
2 hr, 58 min, 59 sec
2 hr, 57 min, 59 sec
2 hr, 56 min, 59 sec
2 hr, 55 min, 59 sec
2 hr, 54 min, 59 sec
2 hr, 53 min, 59 sec
2 hr, 52 min, 59 sec
2 hr, 51 min, 59 sec
2 hr, 50 min, 59 sec
2 hr, 49 min, 59 sec
2 hr, 48 min, 59 sec
2 hr, 47 min, 59 sec
2 hr, 46 min, 59 sec
2 hr, 45 min, 59 sec
2 hr, 44 min, 59 sec
2 hr, 43 min, 59 sec
2 hr, 42 min, 59 sec
2 hr, 41 min, 59 sec
2 hr, 40 min, 59 sec
2 hr, 39 min, 59 sec
2 hr, 38 min, 59 sec
2 hr, 37 min, 59 sec
2 hr, 36 min, 59 sec
2 hr, 35 min, 59 sec
2 hr, 34 min, 59 sec
2 hr, 33 min, 59 sec
2 hr, 32 min, 59 sec
2 hr, 31 min, 59 sec
2 hr, 30 min, 59 sec
2 hr, 29 min, 59 sec
2 hr, 28 min, 59 sec
2 hr, 27 min, 59 sec
2 hr, 26 min, 59 sec
2 hr, 25 min, 59 sec
2 hr, 24 min, 59 sec
2 hr, 23 min, 59 sec
2 hr, 22 min, 59 sec
2 hr, 21 min, 59 sec
2 hr, 20 min, 59 sec
2 hr, 19 min, 59 sec
2 hr, 18 min, 59 sec
2 hr, 17 min, 59 sec
2 hr, 16 min, 59 sec
2 hr, 15 min, 59 sec
2 hr, 14 min, 59 sec
2 hr, 13 min, 59 sec
2 hr, 12 min, 59 sec
2 hr, 11 min, 59 sec
2 hr, 10 min, 59 sec
2 hr, 9 min, 59 sec
2 hr, 8 min, 59 sec
2 hr, 7 min, 59 sec
2 hr, 6 min, 59 sec
2 hr, 5 min, 59 sec
2 hr, 4 min, 59 sec
2 hr, 3 min, 59 sec
2 hr, 2 min, 59 sec
2 hr, 1 min, 59 sec
2 hr, 0 min, 59 sec
1 hr, 59 min, 59 sec
1 hr, 58 min, 59 sec
1 hr, 57 min, 59 sec
1 hr, 56 min, 59 sec
1 hr, 55 min, 59 sec
1 hr, 54 min, 59 sec
1 hr, 53 min, 59 sec
1 hr, 52 min, 59 sec
1 hr, 51 min, 59 sec
1 hr, 50 min, 59 sec
1 hr, 49 min, 59 sec
1 hr, 48 min, 59 sec
1 hr, 47 min, 59 sec
1 hr, 46 min, 59 sec
1 hr, 45 min, 59 sec
1 hr, 44 min, 59 sec
1 hr, 43 min, 59 sec
1 hr, 42 min, 59 sec
1 hr, 41 min, 59 sec
1 hr, 40 min, 59 sec
1 hr, 39 min, 59 sec
1 hr, 38 min, 59 sec
1 hr, 37 min, 59 sec
1 hr, 36 min, 59 sec
1 hr, 35 min, 59 sec
1 hr, 34 min, 59 sec
1 hr, 33 min, 59 sec
1 hr, 32 min, 59 sec
1 hr, 31 min, 59 sec
1 hr, 30 min, 59 sec
1 hr, 29 min, 59 sec
1 hr, 28 min, 59 sec
1 hr, 27 min, 59 sec
1 hr, 26 min, 59 sec
1 hr, 25 min, 59 sec
1 hr, 24 min, 59 sec
1 hr, 23 min, 59 sec
1 hr, 22 min, 59 sec
1 hr, 21 min, 59 sec
1 hr, 20 min, 59 sec
1 hr, 19 min, 59 sec
1 hr, 18 min, 59 sec
1 hr, 17 min, 59 sec
1 hr, 16 min, 59 sec
1 hr, 15 min, 59 sec
1 hr, 14 min, 59 sec
1 hr, 13 min, 59 sec
1 hr, 12 min, 59 sec
1 hr, 11 min, 59 sec
1 hr, 10 min, 59 sec
1 hr, 9 min, 59 sec
1 hr, 8 min, 59 sec
1 hr, 7 min, 59 sec
1 hr, 6 min, 59 sec
1 hr, 5 min, 59 sec
1 hr, 4 min, 59 sec
1 hr, 3 min, 59 sec
1 hr, 2 min, 59 sec
1 hr, 1 min, 59 sec
1 hr, 0 min, 59 sec
59 min, 59 sec
58 min, 59 sec
57 min, 59 sec
56 min, 59 sec
55 min, 59 sec
54 min, 59 sec
53 min, 59 sec
52 min, 59 sec
51 min, 59 sec
50 min, 59 sec
49 min, 59 sec
48 min, 59 sec
47 min, 59 sec
46 min, 59 sec
45 min, 59 sec
44 min, 59 sec
43 min, 59 sec
42 min, 59 sec
41 min, 59 sec
40 min, 59 sec
39 min, 59 sec
38 min, 59 sec
37 min, 59 sec
36 min, 59 sec
35 min, 59 sec
34 min, 59 sec
33 min, 59 sec
32 min, 59 sec
31 min, 59 sec
30 min, 59 sec
29 min, 59 sec
28 min, 59 sec
27 min, 59 sec
26 min, 59 sec
25 min, 59 sec
24 min, 59 sec
23 min, 59 sec
22 min, 59 sec
21 min, 59 sec
20 min, 59 sec
19 min, 59 sec
18 min, 59 sec
17 min, 59 sec
16 min, 59 sec
15 min, 59 sec
14 min, 59 sec
13 min, 59 sec
12 min, 59 sec
11 min, 59 sec
10 min, 59 sec
9 min, 59 sec
8 min, 59 sec
7 min, 59 sec
6 min, 59 sec
5 min, 59 sec
4 min, 59 sec
3 min, 59 sec
2 min, 59 sec
1 min, 59 sec
59 sec
Хорошая особенность DateComponentsFormatter
в том, что она разумно конфигурируется и использует параметры локализации устройств для генерации своего вывода
Вы также можете посмотреть на Останов таймера на определенное время в Swift , который представляет работоспособный пример той же концепции, но также поддерживает возможности паузы / возобновления