nalexn / clean-architecture-swiftui

SwiftUI sample app using Clean Architecture. Examples of working with CoreData persistence, networking, dependency injection, unit testing, and more.
MIT License
5.57k stars 671 forks source link

Access contents of lazylist #39

Closed moh-abk closed 3 years ago

moh-abk commented 3 years ago

Awesome template for clean architecture!

I've the below combine pipeline which is the opposite of way you're handling data in this template; In most real world scenarios;

func refreshCards(id: String) -> AnyPublisher<Void, Error> {
    var cards: [Card] = []
    return gateway
    .listCards(customerID: id)
    .map {
        response in
        response.cards.forEach {
            cards.append(Card(protoObject: $0)!)
        }
        return cards
    }

    .catch {
        err in
        // must return a Publisher
        repository.cards()
    }

    .flatMap {
        [repository] in
        repository.store(cards: $0) // Cannot convert value of type 'LazyList<Card>' to expected argument type '[Card]'
    }

    .eraseToAnyPublisher()
}

repository.store(cards: ) accepts an array of cards - [Card] - how can I unpack LazyList and turn it into an array?

nalexn commented 3 years ago

Hey,

LazyList conforms to Sequence and RandomAccessCollection, so you can do just Array(list)

nalexn commented 3 years ago

You may want to refactor your code and get rid of LazyList in the middle. The main reason for its use in the sample project was to allow for querying and converting CoreData objects to the data model used in the UI lazily for performance reasons.

moh-abk commented 3 years ago

Thanks for quick response @nalexn I don't understand your last comment;

For your first comment, I updated the code to below;

func refreshCards(id: String) -> AnyPublisher<Void, Error> {
    var cards: [Card] = []
    return gateway
    .listCards(customerID: id)
    .map {
        response in
        response.cards.forEach {
            cards.append(Card(protoObject: $0)!)
        }
        return cards // Cannot convert return expression of type '[Card]' to return type 'LazyList<Card>'
    }

    .catch {
        err in
        // must return a Publisher
        repository.cards()
    }

    .flatMap {
        [repository] in
        repository.store(cards: Array($0))
    }

    .eraseToAnyPublisher()
}

But above I now get - Cannot convert return expression of type '[Card]' to return type 'LazyList<Card>'

nalexn commented 3 years ago

You can convert LazyList to Array earlier so the returned container type matches in every step in the chain:

func refreshCards(id: String) -> AnyPublisher<Void, Error> {
    return gateway
    .listCards(customerID: id)
    .map { 
        response in
        return response.cards.map {
            Card(protoObject: $0)!
        }
    }
    .catch {
        err in
        // must return a Publisher
        Array(repository.cards())
    }

    .flatMap {
        [repository] in
        repository.store(cards: $0)
    }

    .eraseToAnyPublisher()
}
moh-abk commented 3 years ago

ended up getting rid of LazyList completely as your code snippet showed other errors and also kept tripping into - https://github.com/nalexn/clean-architecture-swiftui/blob/master/CountriesSwiftUI/Utilities/LazyList.swift#L124;

final code;

return gateway
            .listCards(customerID: id)
            .map { response in
                return response.cards.map {
                    Card(protoObject: $0)!
                }
            }
            .catch { err in
                // must return a Publisher
                repository.cards()

            }
            .flatMap { [repository] in
                repository.store(cards: Array($0))
            }
            .eraseToAnyPublisher()

thanks for the pointers!