Я все еще относительно новичок в Combine и SwiftUI, может быть, я слишком усложняю вещи, но, пожалуйста, держите меня в покое минуту или две.
Одним из требований моего приложения является возможность чтобы запустить несколько таймеров, для целей отчетности.
Я пытался сохранить таймеры и секунды, переданные в @EnvironmentObject
с @Published
переменными, но каждый раз, когда объект обновляется, любое представление, которое наблюдает за @EnvironmentObject
тоже обновляется.
Пример
class TimerManager: ObservableObject {
@Published var secondsPassed: [String: Int]
var timers: [String:AnyCancellable]
func startTimer(itemId: String) {
self.secondsPassed[itemId] = 0
self.timers[itemId] = Timer
.publish(every: 1, on: .main, in: .default)
.autoconnect()
.sink(receiveValue: { _ in
self.secondsPassed[itemId]! += 1
})
}
func isTimerValid(itemId: String) -> Bool {
return self.timers[itemId].isTimerValid
}
// other code...
}
Так, например, если в любом другом представлении мне нужно знать, активен ли конкретный таймер, вызывая функцию isTimerValid
, мне нужно включить это @EnvironmentObject
в это представление, и оно не прекратит обновлять его, потому что таймер меняет secondsPassed
, что составляет Published
, вызывая лаги и бесполезные перерисовки.
Поэтому я сделал одну вещь: кэшируйте itemId
активных таймеров где-то еще, в static
struct
, который я обновляю каждый раз, когда запускаю или останавливаю таймер.
Это выглядело немного глупо, поэтому в последнее время я думал перенести все это в синглтон, как, например,
class SingletonTimerManager {
static let singletonTimerManager = SingletonTimerManager()
var secondsPassed: [String: Int]
var timers: [String:AnyCancellable]
func startTimer(itemId: String) {
self.secondsPassed[itemId] = 0
self.timers[itemId] = Timer
.publish(every: 1, on: .main, in: .default)
.autoconnect()
.sink(receiveValue: { _ in
self.secondsPassed[itemId]! += 1
})
}
// other code...
}
и только для некоторых видов обратите внимание на изменения secondsPassed
. С другой стороны, я могу переместить таймер в фоновом потоке.
Я изо всех сил пытался сделать это правильно.
Это мои Views
(хотя и очень простые Извлечь)
struct ContentView: View {
// set outside the ContentView
var selectedItemId: String
// timerValue: set by a publisher?
var body: some View {
VStack {
ItemView(seconds: Binding.constant(timerValue))
}
}
}
struct ItemView: View {
@Binding var seconds: Int
var body: some View {
Text("\(self.seconds)")
}
}
Мне нужно как-то наблюдать SingletonChronoManager.secondsPassed[selectedItemId]
, чтобы ItemView
обновлялся в реальном времени.
Может кто-нибудь предложить мне способ сделать это?