0

I am trying to do multiple async operations, in sequence, on an array of data. However I am having problems with the return values of map.

Here is the test code:

import Combine

func getLength(_ string: String) -> Future<Int,Error> {
    return Future<Int,Error>{ promise in
        print("Length \(string.count)")
        promise(.success(string.count))
    }
}


func isEven(_ int: Int) -> Future<Bool,Error> {
    return Future<Bool,Error>{ promise in
        print("Even \(int % 2 == 0)")
        promise(.success(int % 2 == 0))
    }
}

let stringList = ["a","bbb","c","dddd"]

func testStrings(_ strings:ArraySlice<String>) -> Future<Void,Error> {
    var remaining = strings
    
    if let first = remaining.popFirst() {
        return getLength(first).map{ length in
            return isEven(length)
        }.map{ even in
            return testStrings(remaining)
        }
    } else {
        return Future { promise in
            promise(.success(()))
        }
    }
}

var storage = Set<AnyCancellable>()

testStrings(ArraySlice<String>(stringList)).sink { _ in } receiveValue: { _ in print("Done") }.store(in: &storage)

This generates the following error:

error: MyPlayground.playground:26:11: error: cannot convert return expression of type 'Publishers.Map<Future<Int, Error>, Future<Void, Error>>' to return type 'Future<Void, Error>'
        }.map{ even in

I thought we could use map to convert from one publisher type to the other, but it seems it's wrapped inside a Publishers.Map. How do I get rid of this?

Thanks!

6
  • See this recent answer of mine. testStrings should not return Future. Commented Dec 4, 2020 at 9:35
  • What should it return then? I tried replacing it with AnyPublisher<Void,Error> and adding .eraseToAnyPublisher() but that gives me other errors Commented Dec 4, 2020 at 9:44
  • Yes that's what you should do. What other error did it give you? Please edit your question with what you changed, and the new error. Commented Dec 4, 2020 at 9:45
  • The issue was I needed to replace the map with flatMap (don't ask me why...) Commented Dec 4, 2020 at 9:47
  • 1
    @JorisMans, map and flatMap are quite different. map emits a mapped value for each upstream value. flatMap maps a publisher for each upstream and emits all the values of that publisher. Commented Dec 4, 2020 at 15:50

1 Answer 1

1

Well it seems that this works:

import Combine

func getLength(_ string: String) -> Future<Int,Error> {
    return Future<Int,Error>{ promise in
        print("Length \(string.count)")
        promise(.success(string.count))
    }
}


func isEven(_ int: Int) -> Future<Bool,Error> {
    return Future<Bool,Error>{ promise in
        print("Even \(int % 2 == 0)")
        promise(.success(int % 2 == 0))
    }
}

let stringList = ["a","bbb","c","dddd"]

func testStrings(_ strings:ArraySlice<String>) -> AnyPublisher<Void,Error> {
    var remaining = strings
    
    if let first = remaining.popFirst() {
        return getLength(first).flatMap{ length in
            return isEven(length)
        }.flatMap{ even in
            return testStrings(remaining)
        }.eraseToAnyPublisher()
    } else {
        return Future<Void,Error> { promise in
            promise(.success(()))
        }.eraseToAnyPublisher()
    }
}

var storage = Set<AnyCancellable>()

testStrings(ArraySlice<String>(stringList)).sink { _ in } receiveValue: { _ in print("Done") }.store(in: &storage)

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.