Мне также пришлось реализовать эту функцию с помощью Combine / SwiftUI: таймер, который будет запускаться при запуске, а затем каждый день, час или минуты (для тестирования), вот мое решение, если оно может быть полезным или улучшено:)
class PeriodicPublisher {
var periodicFormat: PeriodicFormat = .daily
init(_ format: PeriodicFormat = .daily) {
self.periodicFormat = format
}
// Must have an equatable for removeDuplicate
struct OutputDate: Equatable {
let compared: String
let original: String
init(_ comparedDatePart: String, _ originalDate: String) {
self.compared = comparedDatePart
self.original = originalDate
}
static func ==(lhs: OutputDate, rhs: OutputDate) -> Bool {
return lhs.compared == rhs.compared
}
}
enum PeriodicFormat {
case daily
case hourly
case minutely
func toComparableDate() -> String {
switch self {
case .daily:
return "yyyy-MM-dd"
case .hourly:
return "HH"
case .minutely:
return "mm"
}
}
}
func getPublisher() -> AnyPublisher<OutputDate, Never> {
let compareDateFormatter = DateFormatter()
compareDateFormatter.dateFormat = self.periodicFormat.toComparableDate()
let originalTimerDateFormatter = DateFormatter()
originalTimerDateFormatter.dateFormat = "yyyy-MM-dd HH:mm"
var nowDate: Just<OutputDate> {
let comparedDate = compareDateFormatter.string(from: Date())
let originalDate = originalTimerDateFormatter.string(from: Date())
return Just(OutputDate(comparedDate, originalDate))
}
let timerDate = Timer.publish(every: 2.0, tolerance: 1.0, on: .main, in: .default, options: nil)
.autoconnect()
.map { dateString -> OutputDate in
return OutputDate(compareDateFormatter.string(from: dateString), originalTimerDateFormatter.string(from: dateString))
}
.eraseToAnyPublisher()
return Publishers.Merge(nowDate, timerDate)
.map { $0 }
.removeDuplicates()
.eraseToAnyPublisher()
}
}
Как это работает?
Каждые 2 секунды планировщик выпускает текущую дату (с Timer.publi sh ()), эта дата используется для создания «OutputDate» содержит два свойства: одну «сопоставимую» часть, используемую для сравнения, если что-то изменилось, и одну «оригинальную» часть, поэтому она может быть полезна для потребителя.
Свойство Comparable - это дата таймера, отформатированная с toComparableDate с учетом предоставленной конфигурации (.daily, .hourly, .minutely). Использование «removeDuplicates» в этом свойстве позволяет публиковать sh «OutputDate» только при изменении этого значения. Каждый день, час или минуту.
Publishers.Merge используется для публикации sh значения сразу после создания экземпляра, в противном случае ничего не происходит до первого Timer.publi sh (каждый). Здесь 2 секунды.
Как это использовать?
Вы бы использовали это с Combine следующим образом:
PeriodicPublisher(.daily).getPublisher().sink { date in
print("Day has changed \(date.original)")
}