1

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.

DevB1
  • 1,235
  • 3
  • 17
  • 43
  • You aren't using any of Combine's features like `combineLatest` so it would be much simpler to just use SwiftUI's View data structs to do this. – malhal Jan 26 '22 at 19:15

1 Answers1

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
}
Sweeper
  • 213,210
  • 22
  • 193
  • 313