'Swift Combine: Separate published array and then assign
I have a publisher which returns an array of RetailStoreSlotDay objects. I need to separate these out based on a certain property and then assign to separate publishers within the view model.
So, my publisher is:
@Published var selectedDaySlot: RetailStoreSlotDay?
Within the RetailStoreSlotDay object I have a property called 'daytime' which is set to either:
"morning"
"afternoon"
"evening"
I then have these separate publishers that I need to assign values to when the selectedDaySlot is amended:
@Published var morningTimeSlots = [RetailStoreSlotDayTimeSlot]()
@Published var afternoonTimeSlots = [RetailStoreSlotDayTimeSlot]()
@Published var eveningTimeSlots = [RetailStoreSlotDayTimeSlot]()
At the moment, I have the following subscription set up and declared in the init of the view model:
private func setupDeliveryDaytimeSectionSlots() {
$selectedDaySlot
.map { timeSlot in
return timeSlot?.slots
}
.replaceNil(with: [])
.sink(receiveValue: { slots in
self.morningTimeSlots = slots.filter { $0.daytime == "morning" }
self.afternoonTimeSlots = slots.filter { $0.daytime == "afternoon" }
self.eveningTimeSlots = slots.filter { $0.daytime == "evening" }
})
.store(in: &cancellables)
}
This works fine, but I'm sure there must be an operator which will perform this in a more sophisticated way, whereby I can assign the values without using sink. Wondering if there is a better way around this.
Solution 1:[1]
You could group these slots into a dictionary, using Dictionary(grouping:by:):
let dictionaryPublisher = $selectedDaySlot
.map { timeSlot in
Dictionary(grouping: timeSlot?.slots ?? [], by: \.daytime)
}
Then you can assign the values associated with the different keys of the dictionary to the different properties:
dictionaryPublisher.map { $0["morning"] ?? [] }.assign(to: &self.$morningTimeSlots)
dictionaryPublisher.map { $0["afternoon"] ?? [] }.assign(to: &self.$afternoonTimeSlots)
dictionaryPublisher.map { $0["evening"] ?? [] }.assign(to: &self.$eveningTimeSlots)
Rather than using strings as the dayTime values, consider using an enum instead:
enum TimeOfDay: Hashable {
case morning, afternoon, evening
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Sweeper |
