Search code examples
swiftreactive-programmingcombine

Replace nil with Empty or Error in Combine


I have a Combine publisher like this:

enum RemoteError: Error {
    case networkError(Error)
    case parseError(Error)
    case emptyResponse
}

func getPublisher(url: URL) -> AnyPublisher<Entiy, RemoteError> {
    return URLSession.shared
        .dataTaskPublisher(for: url)
        .map(\.data)
        .decode(type: RemoteResponse.self, decoder: decoder)
        .mapError { error -> RemoteError in
            switch error {
            case is URLError:
                return .networkError(error)
            default:
                return .parseError(error)
            }
        }
        .map { response -> Entiy in
            response.enitities.last
        }
        .eraseToAnyPublisher()
}

struct RemoteResponse: Codable {
    let enitities: [Entity]
    let numberOfEntries: Int
}

struct Entity {

}

By the above setting, the compiler complains because response.enitities.last can be nil. The question is can I replace nil with Empty publisher and if not can I replace it with error emptyResponse in Combine chain? The first option is preferable.


Solution

  • You have a couple of options here.

    If you don't want the publisher to publish anything in case entities is empty, you can use coampactMap instead of map:

    .compactMap { response in
       response.entities.last
    }
    

    If you would rather publish an error in such a case you can use tryMap which allows you to throw an Error. You would need mapError to come after it:

    .tryMap { response in
        guard let entity = response.entities.last else {
            throw RemoteError.emptyResponse
        }
        return entity
    }
    .mapError { error -> RemoteError in
        switch error {
        case is URLError:
            return .networkError(error)
        case is DecodingError:
            return .parseError(error)
        default:
            return .emptyResponse
        }
    }