0

This code uses RxSwift

import RxSwift
 
struct Input {
    let loadTrigger: Observable<Void>
}

protocol UseCase {
    func getEventsLists() -> Observable<[EventsList]>
    func saveEventsList(eventsList: EventsList) -> Observable<Void>
}

struct Event {
    let creationDate: Date
}

struct EventsList {
    let events: [Event]
}

var tempEventsList: EventsList? = nil

func example(useCase: UseCase, input: Input, disposeBag: DisposeBag) {
    let events = input.loadTrigger
        .flatMapLatest {
            useCase.getEventsLists()
                .map { $0.first }
                .do(onNext: { eventsList in
                    if eventsList == nil {
                        let eventsList = EventsList(events: [])
                        useCase.saveEventsList(eventsList: eventsList)
                            .subscribe(onNext: {
                                tempEventsList = eventsList
                            })
                            .disposed(by: disposeBag)
                    } else {
                        tempEventsList = eventsList
                    }
                })
                    .map { $0?.events ?? [] }
                    .asDriverOnErrorJustComplete()
        }
}

In my iOS App I can create events to show how much is left to the established date. Every event has their creation date. The events are sorted by the last created (I can change the order manually), so the widget also shows the last created event (I can change the event to show manually).

I would like the list of events to be automatically sorted in chronological order, from newest to oldest.

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
Alessandro
  • 31
  • 1
  • A lot of non-standard functions being called in your code, did you perhaps forget to tag with some 3rd party framework/library you are using? – Joakim Danielson May 06 '23 at 20:53
  • It's in the tag what 3rd party library they are using `rx-swift` this question is fine as it stands. – Daniel T. May 07 '23 at 11:59

1 Answers1

0

There is the simple answer to this question, but also some pointers... One nice thing about using RxSwift is the ability to get away from the "pyramid of doom". Which is when you have nested closures inside nested closures.

You aren't taking advantage of this and as a result are going as much as 8 indents deep trying to get the job done. That isn't necessary and reduces readability. Let's break this code up into separate jobs while answering the question:

First, let's set up an Observable<[EventsList]> variable that emits a new array of events lists every time the loadTrigger fires. Note, we are sharing this value because it is going to be used by more than one stream later:

let eventsLists = input.loadTrigger
    .flatMapLatest { useCase.getEventsLists() }
    .share()

Next, we define exactly when saveEventsList(eventsLists:) is called. The only time it's needed is when getEventsLists() returns an empty array. Presumably this will ensure that the next time it's called, getEventsLists() will return at least one list:

eventsLists
    .filter { $0.isEmpty }
    .map { _ in }
    .subscribe(onNext: {
        _ = useCase.saveEventsList(eventsList: EventsList(events: []))
            .subscribe()
    })
    .disposed(by: disposeBag)

Now, let's define exactly when tempEventsList is assigned to:

eventsLists
    .map { $0.first ?? EventsList(events: []) }
    .subscribe(onNext: { eventsList in
        tempEventsList = eventsList
    })
    .disposed(by: disposeBag)

Lastly, we get our actual Observable array of events. Sorting is simple as you can see:

let events = eventsLists
    .map { $0.first?.events.sorted(by: { $0.creationDate > $1.creationDate }) ?? [] }

All the code together looks like this. Each block of code is an individual and well defined piece of functionality:

let eventsLists = input.loadTrigger
    .flatMapLatest { useCase.getEventsLists() }
    .share()

eventsLists
    .filter { $0.isEmpty }
    .map { _ in }
    .subscribe(onNext: {
        _ = useCase.saveEventsList(eventsList: EventsList(events: []))
            .subscribe()
    })
    .disposed(by: disposeBag)

eventsLists
    .map { $0.first ?? EventsList(events: []) }
    .subscribe(onNext: { eventsList in
        tempEventsList = eventsList
    })
    .disposed(by: disposeBag)

let events = eventsLists
    .map { $0.first?.events.sorted(by: { $0.creationDate > $1.creationDate }) ?? [] }
Daniel T.
  • 32,821
  • 6
  • 50
  • 72