Greetings, traveler!
We continue our series about SwiftUI Week Calendar View. Now, we can create an Observable class to provide and manage data for display.
If you just want to check out the complete source code, here it is.
Week Provider
We will use an Observation
framework. However, if you want to target an iOS version older than 17, you can recreate such a class using the ObservableObject
protocol.
import Foundation
import Observation
@Observable
final class WeekProvider {
}
Storage
The key point of week generation is a reference date. So, let’s create this property.
@Observable
final class WeekProvider {
private var referenceDate: Date = .now
}
Now, create a storage for our weeks. Remember that we will generate only three weeks at a time. So, we can store them inside a dictionary, where the key will be our WeekPosition
enum, and the value will be an array of Week
models.
@Observable
final class WeekProvider {
private(set) var weekDict: [WeekPosition: Week] = [:]
private var referenceDate: Date = .now
}
We should generate this dictionary every time we retrieve a new reference date. To do this, we will use the good old didSet
.
@Observable
final class WeekProvider {
private(set) var weekDict: [WeekPosition: Week] = [:]
private var referenceDate: Date = .now {
didSet {
configureWeeks()
}
}
private func configureWeeks() {
}
}
Weeks
It is time to create a new function to configure our dictionary. This can be done with just one line of code. But before we will do it, let’s return to our WeekPosition
model.
We should add CaseIterable
protocol conformance to use a static allCases
property.
public enum WeekPosition: Int, CaseIterable {
case left = -7
case middle = 0
case right = 7
}
Now, return to the WeekProvider
class. Here, we can create a function for dictionary configuration. We have all we need. We will use the allCases
property and the static week
function we created before. We should call this function during the initialization and whenever we get a new reference date value.
@Observable
final class WeekProvider {
private(set) var weekDict: [WeekPosition: Week] = [:]
private var referenceDate: Date = .now {
didSet {
configureWeeks()
}
}
init() {
configureWeeks()
}
private func configureWeeks() {
weekDict = Dictionary(uniqueKeysWithValues: WeekPosition.allCases.map { ($0, .week(for: referenceDate, at: $0)) })
}
}
Change reference date
As discussed, we have two options for updating our reference date value. The first way is updating the value by scrolling. The second is to get a specific date from outside.
We can create two methods to handle both. To update the value by scrolling, we should use the WeekPosition
enum. We will also use the Date
extension we created earlier.
func update(by position: WeekPosition) {
referenceDate = referenceDate.sameDay(at: position)
}
And to update by a specific date, we can pass this date as a parameter.
func setDate(_ date: Date) {
referenceDate = date.startOfTheDay
}
And that’s it! We automatically update our dictionary every time we update the reference date, so the Views will rerender.
Conclusion
We created a data provider for our views, so it’s a small matter — we need to create these views.
If you enjoyed this article, please feel free to follow me on my social media: